我正在使用EF5并将POCO实体的断开连接图附加到我的上下文中,如下所示: -
using (var context = new MyEntities())
{
context.Configuration.AutoDetectChangesEnabled = false;
context.MyEntities.Attach(myEntity);
// Code to walk the entity graph and set each entity's state
// using ObjectStateManager omitted for clarity ..
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
实体"myEntity"是一个实体的大图,有许多子集合,而这些子集合又有自己的子集合,依此类推.整个图形包含10000个实体的顺序,但通常只更改一小部分.
设置实体状态和实际的代码SaveChanges()
相当快(<200ms).这就是Attach()
问题,需要2.5秒,所以我想知道这是否可以改进.我已经看到了一些文章,告诉你设置AutoDetectChangesEnabled = false
,我正在上面做,但它在我的场景中没有任何区别.为什么是这样?
恐怕 2.5 秒附加一个包含 10000 个实体的对象图是“正常的”。当您附加图表时,可能会发生实体快照创建,这需要花费这段时间。
如果“通常只更改少量”(例如 100),您可以考虑从数据库加载原始实体并更改其属性,而不是附加整个图,例如:
using (var context = new MyEntities())
{
// try with and without this line
// context.Configuration.AutoDetectChangesEnabled = false;
foreach (var child in myEntity.Children)
{
if (child.IsModified)
{
var childInDb = context.Children.Find(child.Id);
context.Entry(childInDb).CurrentValues.SetValues(child);
}
//... etc.
}
//... etc.
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
尽管这将创建大量单个数据库查询,但只会加载没有导航属性的“平面”实体,并且附加(在调用时发生Find
)不会消耗太多时间。要减少查询数量,您还可以尝试使用Contains
查询“批量”加载相同类型的实体:
var modifiedChildIds = myEntity.Children
.Where(c => c.IsModified).Select(c => c.Id);
// one DB query
context.Children.Where(c => modifiedChildIds.Contains(c.Id)).Load();
foreach (var child in myEntity.Children)
{
if (child.IsModified)
{
// no DB query because the children are already loaded
var childInDb = context.Children.Find(child.Id);
context.Entry(childInDb).CurrentValues.SetValues(child);
}
}
Run Code Online (Sandbox Code Playgroud)
这只是一个简化的示例,假设您只需更改实体的标量属性。如果涉及关系的修改(将子项添加到集合中和/或从集合中删除等),它可能会变得更加复杂。