实体框架性能问题将子级添加到列表

时间:2018-12-19 14:16:10

标签: c# list performance entity-framework add

我正在研究一个使用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);
    }
}

1 个答案:

答案 0 :(得分:2)

  

对我来说,Entity Framework加载所有子项只是为了添加一个子项并没有什么意义

当您第一次通过其 getter 访问导航属性时,就会发生惰性加载。还有示例代码

_parent.Children.Add(child);

包含两个操作:

(1)检索Children属性(通过属性 getter !):

var children = _parent.Children;

(2)对其执行一些操作(在这种情况下,调用Add方法)

children.Add(child);

由于操作(1)而发生了延迟加载。如您所见,EF与它无关,因为它无法控制它。而且没有办法知道您要使用该属性值做什么-枚举,计数或使用AddRemove等方法。

以下是一些解决方案。

首先,为什么要完全使用延迟加载?它具有许多副作用和效率低下的问题,而所有这些问题都可以通过通过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); 
    }
}