我正在使用连接到SQL Server 2012数据库的最新EF 6版本。在实际部署中,一切都已经顺利运行了几个月,但我最近添加了一个功能,在添加两个新实体后,我在相同的上下文中两次调用SaveChanges()。
我在模型验证后向我的上下文添加了一个类型为T的实体,然后调用SaveChanges(),该成功没有错误或验证问题。正确插入此实体。
使用相同的上下文,然后我通过复制原始的一些值(大多数是原始类型,但也有一些引用)继续创建类型为T的新实例。这也完全验证并且SaveChanges()不会引发任何错误,但可能有50%的时间,ID仍为0并且没有记录SQL输出,因此未插入实体。
如果我调用Context.Entry(entity),则表示状态为Added,Context.ChangeTracker.Entries在更改列表中返回此新实体。
我创建了一个测试循环,在实体ID为0时连续调用SaveChanges,并且它永远循环而没有错误。
我很难过。我现在可以尝试任何有明智想法的人吗?
编辑:为了证明这是一个合法的问题,我更改了保存代码,以便第二次保存发生在一个全新的上下文中,我重新加载我要插入的第二个实体引用的所有实体。插入每次都成功。因此代码来自在单个上下文中运行的损坏代码:
// insert 'item' if model is valid, should only attempt second insert if first save is successful
if (ModelState.IsValid && this.SaveIsValid(item))
{
var next = item.NextRun(); // create a new run from existing run, copying some data
// save entity to db (insert or update)
this.SaveIsValid(next); // returns true=no errors, but entity NOT inserted
}
使用两个上下文的工作代码:
// insert 'item' if model is valid, should only attempt second insert if first save is successful
if (ModelState.IsValid && this.SaveIsValid(item))
{
// ugly hack workaround because saving twice on the same context sometimes fails
var saved = db;
db = new Models.SanDbContext();
try
{
// create a new run in Running status, and redirect to edit it
var next = item.NextRun();
next.Machine = db.Machines.Find(next.Machine.Id);
next.Operator = db.Users.Find(next.Operator.Id);
next.PartCode = db.PartCodes.Find(next.PartCode.Id);
foreach (var m in next.Measurements)
m.InputType = db.MeasurementTypes.Find(m.InputType.Id);
foreach (var c in next.Coils)
c.Coil = db.SanCoils.Find(c.Coil.Id);
this.SaveIsValid(next); // returns true=no errors, entity inserted
}
finally
{
db.Dispose();
db = saved;
}
}
我可以看到两者之间没有功能差异,但每次都有效,另一半则失败。
编辑2:根据评论中的建议,我想澄清一点,我没有使用任何跟踪查询,因此跟踪所有实体。