zoukankan      html  css  js  c++  java
  • Entity Framework细节追踪

     为了加深对EF特性的了解,so,写了一些测试代码。测试结果也许对实际项目没什么用处,但是对理解EF的相关机制还是有一定帮助的。本文可能会不定期更新(加入新的测试用例=。=)。

    一、事务


     直接看代码。

    1、所有SaveChange包裹在一个TransactionScope里面。

     1 [TestMethod]
     2 public void TestMethod1()
     3 {
     4     using (var entities = new SysProcessEntities())
     5     {
     6         using (TransactionScope scope = new TransactionScope())
     7         {
     8             try
     9             {
    10                 var test = entities.SysUser.Where(o => o.OrganizationID == 1).ToList();
    11                 var test2 = entities.SysRole.ToList();
    12 
    13                 test[0].Code = "admin1";
    14                 test2[0].Name = "dddd";
    15                 entities.SaveChanges();
    16 
    17                 test[0].Code = "admin";
    18                 test2[0].Name = "全功能";
    19                 entities.SaveChanges();
    20 
    21                 scope.Complete();
    22             }
    23             catch (Exception e)
    24             {
    25 
    26             }
    27         }
    28     }
    29 }

    结果:

    2、在1的基础上去掉TransactionScope

     1 [TestMethod]
     2 public void TestMethod1()
     3 {
     4     using (var entities = new SysProcessEntities())
     5     {
     6         var test = entities.SysUser.Where(o => o.OrganizationID == 1).ToList();
     7         var test2 = entities.SysRole.ToList();
     8 
     9         test[0].Code = "admin1";
    10         test2[0].Name = "dddd";
    11         entities.SaveChanges();
    12 
    13         test[0].Code = "admin";
    14         test2[0].Name = "全功能";
    15         entities.SaveChanges();
    16     }
    17 }

    结果:

    3、注释掉2的第9行和第13行,检查单独的一条语句是否自带事务。

     1 [TestMethod]
     2 public void TestMethod1()
     3 {
     4     using (var entities = new SysProcessEntities())
     5     {
     6         var test = entities.SysUser.Where(o => o.OrganizationID == 1).ToList();
     7         var test2 = entities.SysRole.ToList();
     8 
     9         //test[0].Code = "admin1";
    10         test2[0].Name = "dddd";
    11         entities.SaveChanges();
    12 
    13         //test[0].Code = "admin";
    14         test2[0].Name = "全功能";
    15         entities.SaveChanges();
    16     }
    17 }

    结果:

    4、直接写Sql-"update [SysProcess].[dbo].[SysRole] set [name]='全功能' where ID=1",在查询分析器中执行,结果:

    5、将1改为跨数据库

     1 [TestMethod]
     2 public void TestMethod1()
     3 {
     4     using (TransactionScope scope = new TransactionScope())
     5     {
     6         try
     7         {
     8             using (var entities = new SysProcessEntities())
     9             {
    10                 var test = entities.SysUser.Where(o => o.OrganizationID == 1).ToList();
    11                 var test2 = entities.SysRole.ToList();
    12 
    13                 test[0].Code = "admin1";
    14                 test2[0].Name = "dddd";
    15                 entities.SaveChanges();
    16 
    17                 test[0].Code = "admin";
    18                 test2[0].Name = "全功能";
    19                 entities.SaveChanges();
    20             }
    21             using (var entities = new DistributionEntities())
    22             {
    23                 var test = entities.VIPCard.ToList();
    24                 test[0].Sex = true;
    25                 entities.SaveChanges();
    26             }
    27 
    28             scope.Complete();
    29         }
    30         catch (Exception e)
    31         {
    32             string msg = e.Message;
    33         }
    34     }
    35 }

    结果:

    于是整个世界美好了……

    二、AsNoTracking


     注意AsNoTracking要写在最终返回数据的那行代码中才有用,看代码:

     1 [TestMethod]
     2 public void TestMethod9()
     3 {
     4     using (var entities = new SysProcessEntities())
     5     {
     6         var ubs = entities.UserBrand.AsNoTracking();
     7         var obs = entities.OrganizationBrand.Where(ob => ob.OrganizationID == 1).AsNoTracking();
     8         var brands = from ub in ubs
     9                         from ob in obs
    10                         where ub.BrandID == ob.BrandID
    11                         select ub.BrandID;
    12         var test = entities.ProBrand.Where(b => brands.Contains(b.ID)).ToList();
    13         Assert.AreEqual(EntityState.Detached, entities.Entry(test[0]).State);
    14     }
    15 }

    结果:

    so,using之中应该这么写:

    var ubs = entities.UserBrand;
    var obs = entities.OrganizationBrand.Where(ob => ob.OrganizationID == 1);
    var brands = from ub in ubs
                    from ob in obs
                    where ub.BrandID == ob.BrandID
                    select ub.BrandID;
    var test = entities.ProBrand.Where(b => brands.Contains(b.ID)).AsNoTracking().ToList();
    Assert.AreEqual(EntityState.Detached, entities.Entry(test[0]).State);

    三、DbSet.Local


     继续看代码:

    1、

    1 public void TestMethod10()
    2 {
    3     var entities = new SysProcessEntities();
    4     var t1 = entities.ProBoduan.ToList();
    5     var t2 = entities.ProBoduan.ToList();
    6     Assert.AreEqual(t1[0],t2[0]);
    7 }

    大家以为t1[0]是否等于t2[0]?答案是true。可是作为引用类型,我并没有重载它的Equals方法,照理应该为false才对呀。修改下测试代码:

    1 public void TestMethod10()
    2 {
    3     var entities = new SysProcessEntities();
    4     var t1 = entities.ProBoduan.ToList();
    5     var t2 = entities.ProBoduan.ToList();
    6     string name = t2[0].Name;
    7     t1[0].Name = "随便取个名用来测试";
    8     Assert.AreEqual(name, t2[0].Name);
    9 }

    结果:。可知,t1[0]和t2[0]指向的是同一个对象,即t1和t2指向同一个数组地址,也就是entities.ProBoduan.Local指向的地址。不过数据库中,仍执行了两次取数操作。

    2、then,加入AsNoTracking试试看:

    public void TestMethod10()
    {
        var entities = new SysProcessEntities();
        var t1 = entities.ProBoduan.AsNoTracking().ToList();
        var t2 = entities.ProBoduan.AsNoTracking().ToList();
        string name = t2[0].Name;
        t1[0].Name = "随便取个名用来测试";
        Assert.AreEqual(name, t2[0].Name); //true,t1的更改不影响t2,表明t1和t2指向不同地址
    }

    此时entities.ProBoduan.Local.Count为0。

    3、

    1 public void TestMethod10()
    2 {
    3     var entities = new SysProcessEntities();    
    4     var t2 = entities.ProBoduan.FirstOrDefault();
    5     var count1 = entities.ProBoduan.Local.Count;//1
    6     var t1 = entities.ProBoduan.ToList();
    7     var count2 = entities.ProBoduan.Local.Count;//3
    8 }

    将第4行和第6行换下位置。

    1 public void TestMethod10()
    2 {
    3     var entities = new SysProcessEntities();
    4     var t1 = entities.ProBoduan.ToList();
    5     var count1 = entities.ProBoduan.Local.Count;//3   
    6     var t2 = entities.ProBoduan.FirstOrDefault();
    7     var count2 = entities.ProBoduan.Local.Count;//3
    8 }

    四、AutoDetectChangesEnabled & ValidateOnSaveEnabled


     1 public void TestMethod9()
     2 {
     3     using (var entities = new SysProcessEntities())
     4     {
     5         entities.Configuration.AutoDetectChangesEnabled = false;
     6         var ubs = entities.UserBrand;
     7         var obs = entities.OrganizationBrand.Where(ob => ob.OrganizationID == 1);
     8         var brands = from ub in ubs
     9                         from ob in obs
    10                         where ub.BrandID == ob.BrandID
    11                         select ub.BrandID;
    12         var test = entities.ProBrand.Where(b => brands.Contains(b.ID)).ToList();
    13         var t1 = entities.Entry(test[0]).State;
    14         test[0].Description = "ggggg";
    15         var t2 = entities.Entry(test[0]).State;
    16         entities.ProBrand.Remove(test[0]);
    17     }
    18 }

    t1、t2皆为EntityState.Unchanged,原因是entities.Configuration.AutoDetectChangesEnabled = false;若设为true,那么t2将为EntityState.Modified。注意此项设置对Added和Deleted没影响。当我们循环Add大批量数据到上下文中时,设为false将对性能有非常大的提升;该属性设置对循环修改已跟踪实体的属性(entity.Property = XXXX)关系不大,大批量修改已跟踪实体的属性的效率我测试过,非常快(不管是true还是false;当然设为false,然后修改实体属性,没什么意义)。 

    猜测:ValidateOnSaveEnabled表示在SaveChanges()时是否根据映射文件等判断实体是否符合规则(如Key是否被改变,默认已跟踪实体是不能手动改变Key值的等),以后测试!

    转载请注明本文出处:http://www.cnblogs.com/newton/archive/2013/06/03/3115603.html

  • 相关阅读:
    Extjs renderer函数
    孩子,教育,钱
    《新概念英语》的学习方法
    英语,想说爱你爱的太晚
    window.open模拟表单POST提交
    Extjs 解决grid分页bug问题
    Extjs 判断对象是非为null或者为空字符串
    linux shell 删除满足正则表达式的文件
    OpenCV 生成矩形mask
    测试Kaggle kernel commit 是否会删除以前的output
  • 原文地址:https://www.cnblogs.com/newton/p/3115603.html
Copyright © 2011-2022 走看看