Безопасность платформы Entity Framework
Объекты контекста, созданные Entity Framework, не являются потокобезопасными.
Что делать, если я использую два отдельных контекста сущностей, по одному для каждого потока (и вызов SaveChanges()
для каждого) - будет ли это потокобезопасным?
// this method is called from several threads concurrently
public void IncrementProperty()
{
var context = new MyEntities();
context.SomeObject.SomeIntProperty++;
context.SaveChanges();
}
Я считаю, что сущность framework context реализует какую-то переменную 'counter', которая отслеживает, являются ли текущие значения в контексте свежими или нет.
- С приведенным выше кодом - вызванный из отдельных потоков - мне все еще нужно блокировать инкремент /savechanges?
- Если да, то каков предпочтительный способ выполнить это в этом простом сценарии?
Ответы
Ответ 1
Более того, один поток, работающий в одном контексте Entity Framework, не является потокобезопасным.
Отдельный экземпляр контекста для каждого потока является потокобезопасным. Пока каждый поток выполнения имеет свой собственный экземпляр EF-контекста, вы будете в порядке.
В вашем примере вы можете вызывать этот код из любого количества потоков одновременно, и каждый из них будет счастливо работать со своим собственным контекстом.
Однако я бы предложил реализовать блок "using" для этого следующим образом:
// this method is called from several threads concurrently
public void IncrementProperty()
{
using (var context = new MyEntities())
{
context.SomeObject.SomeIntProperty++;
context.SaveChanges();
}
}
Ответ 2
Я верю, что "SomeObject.SomeIntProperty" является статическим. Это не имеет ничего общего с тем, что Entity является потокобезопасным. Если вы пишете переменные Static в многопоточной среде, вы всегда должны обертывать их двойной блокировкой для обеспечения безопасности потоков.
Ответ 3
Вы можете использовать подход factory, введя свой DbContext как factory вместо экземпляра perse, посмотрите на это: https://github.com/vany0114/EF.DbContextFactory
Это безопаснее, и вы избегаете жесткого кодирования создания экземпляра в своих репозиториях.
http://elvanydev.com/EF-DbContextFactory/
Существует расширение для Ninject, чтобы сделать это очень просто, просто вызывая метод kernel.AddDbContextFactory<YourContext>();
, вам также нужно изменить свой репозиторий, получив Func<YourContext>