2015-09-05 4 views
6

Мне нужно обновить несколько таблиц в моей БД за одну транзакцию, и я прочитал, что это способ сделать это с помощью DbContext.SaveChanges.Entity Framework DbContext и безопасность потоков

Однако я также читал, что срок службы DbContext должен быть как можно короче, поскольку он растет с течением времени, когда он загружает больше объектов.

Также я прочитал, что для обеспечения безопасности потока каждое действие должно иметь свой собственный DbContext.

Должен ли я иметь DbContext для каждой таблицы, которую я хочу изменить, и позвоните по номеру SaveChanges на каждом DbContext? Не будут ли последние SaveChanges отменять изменения предыдущих вызовов?

Каков наилучший способ сделать это? (Мне нужно это для веб-сайта)

+0

Если вы хотите сделать все это за одну транзакцию, тогда один DbContext будет в порядке. Не нужно беспокоиться о безопасности потоков, хотя вам нужно будет делать все ваши операции последовательно. – DavidG

+0

@DavidG: Но что, если 2 пользователя попытаются использовать один и тот же DbContext одновременно? Не будет ли причиной гонки? – Idov

+0

Вы никогда не должны допускать, чтобы это произошло. DbContext не предназначен для использования таким образом и будет делать некоторые очень странные вещи, если вы попытаетесь! – DavidG

ответ

1

Простой способ состоит в том, чтобы иметь один DbContext для каждого запроса, ASP.NET MVC выполняет всю безопасность потоков, каждый экземпляр контроллера в ASP.NET MVC изолирован для каждого запроса, вы не приходится беспокоиться о состоянии гонки. Пока вы не создаете потоки и просто выполняете преобразование данных в методе действий с использованием одного DbContext, у вас не будет проблем.

В основном DbContext ничего не делает, он просто ставит запрос SQL в целевую базу данных, это база данных, которая обрабатывает многопоточность, условия гонки. Чтобы защитить ваши данные, вы должны использовать транзакции и добавлять проверки в базе данных, чтобы убедиться, что они будут сохранены правильно

public abstract class DbContextController : Controller{ 

    public AppDbContext DB { get; private set;} 

    public DbContextController(){ 
     DB = new AppDbContext(); 
    } 

    protected override void OnDisposing(bool disposing){ 
     DB.Dispose(); 
    } 

} 

Если вы унаследовали любой класс из DbContextController и использовать БД в течение всей жизни контроллера, вы не будете иметь любая проблема.

public ActionResult ProcessProducts(){ 
    foreach(var p in DB.Products){ 
     p.Processed = true; 
     foreach(var order in p.Orders){ 
      order.Processed = true; 
     } 
    } 
    DB.SaveChanges(); 
} 

Однако, если вы используете какую-либо тему, как в следующем примере,

public ActionResult ProcessProducts(){ 
    Parallel.ForEach(DB.Products, p=>{ 
     p.Processed = true; 
     // this fails, as p.Orders query is fired 
     // from same DbContext in multiple threads 
     foreach(var order in p.Orders){ 
      order.Processed = true; 
     } 
    }); 
    DB.SaveChanges(); 
} 
1

Entity Framework is not thread-safe. An MVC controller is instantiated per request. Таким образом, если вы используете один DbContext для каждого запроса, вы будете в безопасности до тех пор, пока не будете вручную создавать потоки в действиях вашего контроллера (чего вы не должны делать в любом случае).

Теперь, если у вас есть concurrency, как система бронирования, в которой несколько пользователей могут получить доступ к тем же ограниченным ресурсам, которые могут закончиться (например, билеты), вам придется реализовать логику вокруг себя. Никакая безопасность нитей не поможет вам в любом случае.

Вот почему вас просят ввести код в комментариях, потому что объяснение безопасности потоков в целом слишком широк и, вероятно, не применимо к вашей ситуации.

Смежные вопросы