JK.*_*JK. 1 asp.net-mvc performance linq-to-entities entity-framework
我有一个问题,如果不应该将子对象添加到父对象异常缓慢.有成千上万个子对象(在这种情况下为33k记录),但这些对象都不是父对象的子对象.
当我将第一个孩子添加到父母时,需要一分钟以上才能完成:
public class ParentEntity // POCO generated by EF TT4 templates
{
public virtual int Id { get; set; }
public virtual ICollection<ChildEntity> ChildEntities {}
}
public class ChildEntity // POCO generated by EF TT4 templates
{
public virtual int Id { get; set; }
public virtual int ParentEntityId { get; set; }
public virtual ParentEntity ParentEntity { get; set; }
public virtual Warehouse Warehouse { get; set; }
public virtual WarehouseLocation WarehouseLocation { get; set; }
}
public class Warehouse { // etc } // another POCO class
public class WarehouseLocation { // etc } // another POCO class
// somewhere in a controller action method...
var parent = _parentEntityService.GetBy(id);
var child = new ChildEntity{ ParentEntityId = id,
WarehouseId = id2, WarehouseLocationId = id3 };
// ChildEntities.Add() takes more than one minute to add the
// first and only child to this parent
// why would this be so incredibly slow?
parent.ChildEntities.Add(child);
Run Code Online (Sandbox Code Playgroud)
在EntityFramework中找到速度问题的最佳方法是什么?
更新:EFProf显示它发出三个SQL查询:
SELECT * FROM ChildEntities where ParentId = id
SELECT * FROM ChildEntities where WarehouseId = id2
SELECT * FROM ChildEntities where WarehouseLocation = id3
Run Code Online (Sandbox Code Playgroud)
为什么它只为每个ChildEntity加载这些,当它只应为当前子项加载它们时?
编辑2:根据@LadislavMrnka,额外的查询是由模板的Fixup方法引起的.但是当我注释掉那些方法并注释掉对Fixup的调用时,它仍然很慢.这不是删除修复的正确方法(看起来它被移除给我):
public class ChildEntity {
public virtual Warehouse Warehouse
{
get { return _warehouse; }
set
{
if (!ReferenceEquals(_warehouse, value))
{
var previousValue = _warehouse;
_warehouse = value;
//FixupWarehouse(previousValue); // commented out
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是你的问题:
var child = new ChildEntity
{
Foo = "",
Bar = "",
ParentEntityId = id,
WarehouseId = 1,
WarehouseLocationId = 1
};
parent.ChildEntities.Add(child);
Run Code Online (Sandbox Code Playgroud)
恕我直言,这是关于隐藏在POCO模板生成的代码中的修复集合.Fixup +延迟加载=性能问题.Fixup尝试使模型中的所有内容保持同步.这意味着如果您设置导航属性或FK属性的一侧,它将尝试确保关系另一侧的导航属性也反映了更改.问题是如果没有加载导航属性,它将触发延迟加载.在您的情况下,看起来设置Warehouse首先修复了导航属性,ChildEntity然后尝试修复Warehouse实例上的导航属性,但其子实体集合未加载=>延迟加载导致
SELECT * FROM ChildEntities where WarehouseId = some id
Run Code Online (Sandbox Code Playgroud)
同样的情况发生在WarehouseLocation.第一个查询是在父实体上将子项添加到未加载的集合的结果.
解决方案是修改模板并删除所有修正(例如,EFv4.1的DbContext POCO模板+不再使用修正)或通过调用以下命令关闭延迟加载:
context.ContextOptions.LazyLoadingEnabled = false;
// Your insert logic here
context.ContextOptions.LazyLoadingEnalbed = true;
Run Code Online (Sandbox Code Playgroud)
您甚至可以将代码包装在自定义IDisposable中,如:
public class DisableLazyLoadingScope : IDisposable
{
private readonly ObjectContext context;
public DisableLazyLoadingScope(ObjectContext context)
{
this.context = context;
context.ContextOptions.LazyLoadingEnabled = false;
}
public void Dispose()
{
context.ContextOptions.LazyLoadingEnabled = true;
}
}
Run Code Online (Sandbox Code Playgroud)
并使用它像:
using (new DisableLazyLoadingScope(context)
{
// Your insert logic here
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1284 次 |
| 最近记录: |