【问题标题】:Speeding Up Entity Framework 4.2 POCO加速实体框架 4.2 POCO
【发布时间】:2011-11-17 16:51:00
【问题描述】:

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

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

一个

  • AId(int - 非空 - 标识 - 主键)
  • 名称(nvarchar(50) - 非空)

B

  • BId(int - 非空 - 标识 - 主键)
  • SomeValue(int - 非空)
  • AId(int - 非空 - 连接到表 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 秒!

我非常感谢任何能让这件事更快发生的提示。非常感谢!

【问题讨论】:

    标签: c# .net performance entity-framework


    【解决方案1】:

    导航属性的世界可能是一个痛苦的世界。我们基本上不得不逐步停止使用它们,因为它们会在你背后造成很多性能问题(尤其是当你开始附加和分离实体时,但那是另一回事了)。

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

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

    【讨论】:

      【解决方案2】:

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

      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 关键字或在上下文构造函数中禁用延迟加载。

      【讨论】:

        猜你喜欢
        • 2011-08-21
        • 2012-03-08
        • 1970-01-01
        • 2012-03-22
        • 1970-01-01
        • 2011-03-04
        • 2016-03-17
        • 2016-01-28
        • 2011-08-24
        相关资源
        最近更新 更多