zoukankan      html  css  js  c++  java
  • AutoDetectChangesEnabled及AddRange解决EF插入的性能问题

    转自:http://www.cnblogs.com/nianming/archive/2013/06/07/3123103.html#2699851

    记录下。

    园友莱布尼茨写了一篇《Entity Framework数据插入性能追踪》的文章,我感觉不错,至少他提出了问题,写了出来,引起了大家的讨论,这就是一个氛围。读完文章+评论,于是我自己也写了个简单的程序试了试。

    先晒一下代码:

    两个简单的类:

     1:      /// <summary>
       2:      /// 消费者
       3:      /// </summary>
       4:      public class Consumer
       5:      {
       6:          public int CId { get; set; }
       7:          public string CName { get; set; }
       8:          public List<Order> Orders { get; set; }
       9:      }
      10:   
      11:      /// <summary>
      12:      /// 订单
      13:      /// </summary>
      14:      public class Order
      15:      {
      16:          public int OrderNo { get; set; }
      17:          public DateTime OrderDate { get; set; }
      18:          public decimal TotalMoney { get; set; }
      19:          public int CId { get; set; }
      20:   
      21:          public Consumer Consumer { get; set; }
      22:      }
     
    
     
    
    映射配置:
    
       1:      public class ConsumerConfiguration : EntityTypeConfiguration<Consumer>
       2:      {
       3:          public ConsumerConfiguration()
       4:          {
       5:              HasKey(t => t.CId).Property(t => t.CId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
       6:              Property(t => t.CName).IsRequired().HasMaxLength(50);
       7:          }
       8:      }
       9:   
      10:      public class OrderConfiguration : EntityTypeConfiguration<Order>
      11:      {
      12:          public OrderConfiguration()
      13:          {
      14:              HasKey(t => t.OrderNo);
      15:              HasRequired(t => t.Consumer).WithMany(t => t.Orders).HasForeignKey(t => t.CId);
      16:          }
      17:      }
     
    Context:
    
       1:      public class TestContext : DbContext
       2:      {
       3:          public DbSet<Consumer> Consumers { get; set; }
       4:          public DbSet<Order> Orders { get; set; }
       5:   
       6:          protected override void OnModelCreating(DbModelBuilder modelBuilder)
       7:          {
       8:              modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
       9:   
      10:              modelBuilder.Configurations.Add(new ConsumerConfiguration());
      11:              modelBuilder.Configurations.Add(new OrderConfiguration());
      12:   
      13:              base.OnModelCreating(modelBuilder);
      14:          }
      15:      }
    测试代码:
    
       1:          static void Main(string[] args)
       2:          {
       3:              using (var ctx = new TestContext())
       4:              {
       5:                  ctx.Consumers.Add(new Consumer()
       6:                  {
       7:                      CName = "张三"
       8:                  });
       9:                  ctx.SaveChanges();
      10:   
      11:                  Stopwatch sw = new Stopwatch();
      12:                  sw.Start();
      13:                  Console.WriteLine("订单开始:
    ");
      14:   
      15:                  for (int outer = 0; outer < 20000; outer++)
      16:                  {
      17:                      ctx.Orders.Add(new Order()
      18:                            {
      19:                                OrderDate = DateTime.Now,
      20:                                TotalMoney = 100,
      21:                                CId = 1,
      22:                            });
      23:                  }
      24:                  ctx.SaveChanges();
      25:                  sw.Stop();
      26:                  Console.WriteLine(sw.Elapsed.Minutes + "" + sw.Elapsed.Seconds + "" + sw.Elapsed.Milliseconds + "毫秒");
      27:              }
      28:          }
     

    上面的代码是最平常的代码了,没有什么可解释的,将内容放到重点上。

    运行以上代码的环境是VS2012+SQL SERVER 2008 R2,机器配置:4G,N年以前的CPU。

    运行上面的代码非常的慢,正如莱布尼茨说的,在数据Add到上下文这个阶段比较耗时。出现这个问题的原因是:每次调用ctx.Orders.Add(order)之前,EF都会调用DetectChanges,在StackOverFlow上有解释,地址是:http://stackoverflow.com/questions/9439430/improving-performance-of-initializing-dbset-in-seed,另外在Programming Entity Framework DbContext这本书的60也有DetectChange的介绍。

    解决上面速度慢的问题的办法就是设置

       1:  ctx.Configuration.AutoDetectChangesEnabled = false;

    下面来看看禁用以后的执行速度:

    QQ截图20130607002820

    另外一个解决办法就是使用DbSet<T>.AddRange方法,这个方法是在6.0 beta1中加入的。

     1:                  List<Order> orderList = new List<Order>();
       2:                  for (int outer = 0; outer < 20000; outer++)
       3:                  {
       4:                      orderList.Add(new Order()
       5:                             {
       6:                                 OrderDate = DateTime.Now,
       7:                                 TotalMoney = 100,
       8:                                 CId = 1
       9:                             });
      10:                  }
      11:                  ctx.Orders.AddRange(orderList);
      12:                  ctx.SaveChanges();

    QQ截图20130607004003

    AddRange方法在System.Data.Entity 泛型DbSet类中,下图是我通过Reflector截的图

    QQ截图20130607004407

    QQ截图20130607004652

    从上面两幅图中可以看到,Add和AddRange都是添加到_internalSet中,但是如果AutoDetectChangesEnabled设置为true的话,添加任何实体之前都会调用DetectChanges,注意看Remarks中的解释。

  • 相关阅读:
    C#操作Windows控制面板
    WPF打印控件内容
    LINQ函数
    通过实现System.IComparable接口的CompareTo方法对两个类进行比较
    泛型和约束
    CSS样式基础总结
    C#调用百度高精度IP定位API通过IP获取地址
    软件下载路径
    RNN学习资料
    mysql 不能插入中文记录
  • 原文地址:https://www.cnblogs.com/ceci/p/4381075.html
Copyright © 2011-2022 走看看