【发布时间】:2011-05-05 00:52:42
【问题描述】:
我正在使用 EF 4,POCO。任务如下:拥有一长串 DomainObject 类型的数据,需要从数据库中获取并在断开连接的模式下进行更新(添加、更新、删除操作)。以后如何将更新的集合推回数据库?假设自从我们加载数据以来,表没有并行更改。我知道 context.SaveChanges() 进行更新,但问题是如何将所有更改从有点列表中放回 DbSet,或者是否有办法在断开连接模式下直接使用 DbSet?谢谢!
【问题讨论】:
我正在使用 EF 4,POCO。任务如下:拥有一长串 DomainObject 类型的数据,需要从数据库中获取并在断开连接的模式下进行更新(添加、更新、删除操作)。以后如何将更新的集合推回数据库?假设自从我们加载数据以来,表没有并行更改。我知道 context.SaveChanges() 进行更新,但问题是如何将所有更改从有点列表中放回 DbSet,或者是否有办法在断开连接模式下直接使用 DbSet?谢谢!
【问题讨论】:
自我跟踪实体是 EDMX + ObjectContext API 的功能,因此如果您的映射/代码依赖于 DbContext API(您提到了DbSet),您将无法使用它们。自跟踪实体是变更集模式的实现(如旧数据集)。关于 SO 的一些参考:
如果您不使用自跟踪实体,答案非常简单 - 您必须告诉 EF 您做了哪些更改。使用分离实体后,您必须将实体附加回新上下文并手动准确说出您所做的 = 插入、更新、删除的内容以及如何更改关系。此过程中的关键组件是 ObjectContext API 中的 ObjectStateManager (context.ObjectStateManager) 或 DbContext API 中的 DbChangeTracker (context.ChangeTracker)。这在处理关系时非常困难,我们中的许多人通常使用另一个过程:我们再次加载实体图并将分离实体图的更改合并到附加实体图。一些参考资料:
请注意,您的整个过程可能会非常缓慢,具体取决于您要执行的更新数量。原因是EF doesn't support command batching 所以每次插入、更新、删除都是在单独的数据库往返中执行的。如果您更新 100.000 个复杂对象,您可以预期 SaveChanges 的执行需要几分钟时间。
编辑:
在一些非常特殊的场景中,您只使用没有关系的实体,您可以使用技巧来传输有关“更改”的信息:
public void ProcessChanges(IEnumerable<DomainObject> entities)
{
foreach(var entity in entities)
{
if (entity.Id == 0)
{
// New entity
}
else if (entity.Id > 0)
{
// Modified entity (you cannot say if entity war really modified,
// you must update it always).
}
else
{
// Use negative Id (origId * -1) to mark entity as deleted
// reverse Id and delete entity
}
}
}
这仅适用于具有简单键的平面对象。
【讨论】:
DbSet 上执行插入和删除有什么问题?
【讨论】: