当我从未将实体添加到上下文时,实体框架错误地保存了它
Posted
技术标签:
【中文标题】当我从未将实体添加到上下文时,实体框架错误地保存了它【英文标题】:Entity Framework incorrectly saving an entity when I never added it to the Context 【发布时间】:2010-12-16 04:45:23 【问题描述】:我在 .NET 4.0 中使用实体框架。我有一个Subscription
实体,它有许多CFile
实体。我创建了一个新的CFile
实体,但从未实际调用过AddObject
。后来我尝试保存与之相关的Subscription
实体,EF 尝试保存CFile
实例,这是我从未想过的!
简化代码:
var subscription = new Subscription();
Context.Subscription.AddObject(subscription);
Context.SaveChanges();
var cfile = new CFile() Subscription = subscription ;
if (SomeChecksPass(cfile))
Context.CFiles.AddObject(cfile);
else
// No AddObject!
subscription.SomeProperty = "changed";
Context.SaveChanges(); // Saves cfile as well, even if I don't want to!
我明白为什么会发生这种情况,但我如何才能不这样做呢?这会产生一个相当微妙和晦涩的错误(实际代码显然要复杂得多)。我希望它只保存我明确传递给AddObject
的实体。
我还知道一种解决方法:在我不想保存的实体上调用 Detach
。但是,这不是一个好的解决方法,因为我必须确保在未保存 cfile
的每个可能的代码路径中调用 Detach(并且在某些代码路径中它被保存),因此必须在该决定之后调用它已制作,但在保存其他任何内容之前。这很脆弱,我真的不想依赖它。
编辑: cfile
被创建是因为我大部分确实想保存它,但如果某些验证失败或发生错误,那么我不会.不过,我仍然想保存对 subscription
对象的一些更改。
【问题讨论】:
您是否有机会使用自我跟踪实体?还是您使用的是开箱即用(代码生成)EF4?我猜你正在使用 STE,并且由于你更新了一个 CFile(被跟踪),EF 正在将它添加到图表中。尝试将new CFile()
移到您的 using
语句之外(如果您使用的话)。
不,它们不是自我跟踪实体,我没有使用using
声明。 (我会在 using
中包含哪个对象?我还是 EF 的新手。)
通常你会将上下文对象包含在 using 语句中。
我意识到这是一个简化的示例,但是有关您通过创建 cfile
尝试实现的目标的更多信息可能会有所帮助。只是想知道,如果您不将对象保存在数据库中,为什么要创建对象(作为实体图的一部分)。至于 EF 行为,这正是人们在这种情况下所期望的,如果它的行为不同,我会感到惊讶。也就是说,您确实需要破解或解决方法来诱导特定行为。一种方法是 Detach
对象,另一种可能是更改 ObjectStateManager
中的状态。
如果您在创建CFile
的地方调用Detach
,然后它只会保存在您当前有代码保存它的地方,怎么样?
【参考方案1】:
尝试在您的 EDMX 中公开外键(如果还没有的话)并执行以下操作:-
var cfile = new CFile() SubscriptionId = subscription.Id ;
这应该足以防止对象图的形成。
您可能需要在创建订阅对象后调用 Refresh(取决于您的 ID 是如何生成的 - 大多数将在您 SaveChanges() 时自动更新)。
【讨论】:
【参考方案2】:您不能直接控制要在 Entity Framework 中保存哪些实体,它会保存它认为应该保存的内容,它与关联的对象图一起使用。您可以使用 ObjectStateManager 在 ObjectContext.SaveChanges 覆盖中添加一些逻辑,但这很丑陋。
如果您需要更多地控制要保存的内容和时间,也许最好使用其他模式,例如 Repository | ActiveRecord,您可以更好地控制单独的实体。或者您会经常发现自己处于您所描述的情况。
【讨论】:
【参考方案3】:我在使用时遇到了同样的问题:
List<Ey> eys = dc.Context.Ey.ToList();
eys = eys .Where(h => h.Employee == myEmployee).ToList();
Ey esh;
for (int k = 1; k < 5; k++)
EmployeeSkillHistory duplicate = histories.Where(h => h.Sl == esh.Sl).FirstOrDefault();
if (duplicate == null)
dc.Context.Ey.AddObject(esh); else dc.Context.Ey.DeleteObject(esh);
dc.Context.SaveChanges();
使用前
else dc.Context.Ey.DeleteObject(esh);
副本已保存在我的数据库中
【讨论】:
以上是关于当我从未将实体添加到上下文时,实体框架错误地保存了它的主要内容,如果未能解决你的问题,请参考以下文章