我正在研究一个使用Entity Framework 6.1.3的项目。现在,在将子对象添加到父实体列表中时,我们遇到了相当大的性能问题(请参见下面的代码示例)。
我们正在使用延迟加载,因此我注意到在调用_parent.Children.Add(child);
之前一切正常,因为它似乎是从数据库加载所有子项只是为了能够添加一个新子项。由于我们的某些父对象大约有50,000个子对象,因此,此简单的插入调用将延迟7-8秒,有时甚至会导致超时。
对我来说,仅为了添加一个子框架而加载所有子框架并没有真正意义,所以有没有办法避免这种情况,或者这是一个Entity Framework设计缺陷,我们是否应该找到解决方法?
我显然很想为此找到解决方案,并且宁愿不必为此问题实现纯ADO查询。
谢谢!
public class Parent
{
public Guid Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public Guid Id { get; set; }
}
public class ParentAggregate
{
private readonly Parent _state;
public ParentAggregate(Parent state)
{
_state = state;
}
public void AddChild(Guid id)
{
var child = new Child { Id = id };
_state.Children.Add(child);
}
}
答案 0 :(得分:2)
对我来说,Entity Framework加载所有子项只是为了添加一个子项并没有什么意义
当您第一次通过其 getter 访问导航属性时,就会发生惰性加载。还有示例代码
_parent.Children.Add(child);
包含两个操作:
(1)检索Children
属性(通过属性 getter !):
var children = _parent.Children;
(2)对其执行一些操作(在这种情况下,调用Add
方法)
children.Add(child);
由于操作(1)而发生了延迟加载。如您所见,EF与它无关,因为它无法控制它。而且没有办法知道您要使用该属性值做什么-枚举,计数或使用Add
,Remove
等方法。
以下是一些解决方案。
首先,为什么要完全使用延迟加载?它具有许多副作用和效率低下的问题,而所有这些问题都可以通过通过Include
方法立即加载的EF轻松解决。这就是为什么默认情况下EF Core(“ EF的未来”)默认情况下不使用延迟加载,并且需要特殊的程序包和过程来启用它。
第二,如果您坚持使用延迟加载,则有以下两种选择:
(A)在数据修改期间禁用延迟加载(需要访问/控制DbContext
实例):
dbContext.Configuration.LazyLoadingEnabled = false;
_parent.Children.Add(child);
dbContext.Configuration.LazyLoadingEnabled = true;
这还需要初始化collection属性以避免NRE。
(B)使用显式后备字段并提供对其的一些直接访问(以避免由属性访问器触发延迟加载)。例如:
public class Parent
{
public Guid Id { get; set; }
private ICollection<Child> children;
public virtual ICollection<Child> Children { get => children; set => children = value; }
public void Add(Child child)
{
// use the backing field directly
if (children == null) children = new HashSet<Child>();
children.Add(child);
}
}