我在使用代码优先方法的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()