是具有EF Savechanges的读取提交快照,导致竞争条件



我在使用代码优先方法的EF6中遇到问题,其中试图访问实体的新DB上下文导致空引用异常。下面是我的场景示例:

主线程

int personId = 0;
using(var ctx = new exampleContext())
{
var person = new Person() {Name = "Alex"};
ctx.People.Add(person);
ctx.SaveChanges();
personId = person.id;
}
Task.Run(() => {someOtherThread(personId)})

其他线程

public static someOtherThread(int personId)
{
using(var ctx = new exampleContext())
{
var person = ctx.People.Where(x => x.id == personId);
//Exception here.
var name = person.Name;
}
}

当我在DB中关闭Is Read Committed Snapshot选项时,这将按预期工作(在EF创建DB时默认打开(,但我们希望尽可能保持最乐观的并发控制模型。

我认为发生的情况是SaveChanges没有等待在数据库上创建新的快照,因此其他线程正在读取旧的快照。

请注意,如果我让线程休眠,直到它能够获得记录,它最终会休眠,这样SaveChanges就不会默默地失败。

这里有我遗漏的东西吗?这可能是EF的错误吗?还是如预期的那样有效?如果它按预期工作,那么解决这一问题的最佳做法是什么?

谢谢!

它返回null是因为。Add并没有将更改写入数据库,因此您必须首先使用SaveChanges(),然后才能通过尝试的方式访问新人员的id。

var person = new Person() {Name = "Alex"};
ctx.People.Add(person);
personId = person.id;

代码中应该是

var person = new Person() {Name="Alex"};
ctx.People.Add(person);
ctx.SaveChanges();
personId=person.id;

此外,如果在personId上设置断点,则会看到值返回0,直到调用SaveChanges()

最新更新