加速实体框架4.2 POCO

时间:2011-11-17 16:51:00

标签: c# .net performance entity-framework

我使用的是Entity Framework 4.2,我遇到了相当严重的性能问题。我正在使用POCO方法,继承自DbContext,这是一个解释问题的小样本:

我有一个包含2个表的数据库 - A和B:

A

  • AId(int - not null - identity - primary key)
  • 名称(nvarchar(50) - 非null)

  • BId(int - not null - identity - primary key)
  • SomeValue(int - not null)
  • AId(int - not null - 连接到表A中的AId的外键)

A中有一行(1,'Test'),B有6000行(SomeValue只是0到5999之间的数字) - 所有这些都通过外键列引用A行。

我从数据库创建一个edmx并关闭代码生成。然后我创建以下类:

public class DatabaseContext : DbContext
{
    public DatabaseContext(string name) : base(name)
    {
        Configuration.AutoDetectChangesEnabled = false;
        As = Set<A>();
        Bs = Set<B>();
    }

    public DbSet<A> As { get; private set; }
    public DbSet<B> Bs { get; private set; }
}

public class A
{
    public virtual int AId { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<B> Bs { get; private set; }

    public void AddB(B b)
    {
        if (b == null)
        {
            throw new ArgumentNullException("b");
        }

        if (Bs == null)
        {
            Bs = new List<B>();
        }

        if (!Bs.Contains(b))
        {
            Bs.Add(b);
        }

        b.A = this;
    }
}

public class B
{
    public virtual int BId { get; set; }
    public virtual A A { get; set; }
    public virtual int SomeValue { get; set; }
}

现在我只需执行以下操作:

var ctx = new DatabaseContext("ScalabilityTestEntities");
var a = ctx.As.FirstOrDefault();
a.Bs.Add(new B { SomeValue = 987 });

最后一行(我添加一个新的B)在我的四核,4gb RAM 64位Windows 7机器上占用6秒的区域,该机器在本地运行数据库。

真正糟糕的是它似乎会以指数方式降低某些因素,因为如果你将B中的行数加倍,则需要接近20秒!

我真的很感激有任何提示可以让这种情况更快发生。非常感谢!

2 个答案:

答案 0 :(得分:4)

导航属性的世界可能是痛苦的。我们基本上不得不逐步停止使用它们,因为它们背后会导致很多性能问题(特别是当你进入附加和分离实体时,但这是一个不同的故事)。

当您访问a.Bs时,它会加载该A的所有B。

在这种特殊情况下,如果你实际上并不需要B的完整列表而你只想添加一个新的B,那么最好简单地创建一个B并将其AId设置为一个ID。

答案 1 :(得分:3)

在这种情况下,您应该禁用延迟加载:

var ctx = new DatabaseContext("ScalabilityTestEntities");
ctx.Configuration.LazyLoadingEnabled = false;
var a = ctx.As.FirstOrDefault();
a.Bs = new List<B>();
a.Bs.Add(new B { SomeValue = 987 });

默认情况下启用延迟加载(导致访问集合时会加载所有6000个B),因为导航集合声明为virtual。如果您从不需要或想要使用延迟加载,则应完全删除virtual关键字或在上下文构造函数中禁用延迟加载。