• 第二节:EF Core的常规“增删改”及状态的变化


    一. 整体说明

    1. 本节用到的表

     

    2. 状态说明补充

     ①.Detached: 游离的状态,与数据库没有什么交涉,比如新new一个实体,状态就是Detached。

     ②.Added: 增加的状态。

     ③.Deleted: 删除的状态。

     ④.Modified: 修改的状态。

     ⑤.Unchanged: 与数据库内容相比,未发生变化时的状态,从数据库中查询出来的对象就是Unchanged状态。

    PS:查询出来的实体,AsNoTracking一下,就变成Detached游离状态了 。

    1  using (DbContext db = new EFDB01Context())
    2  {
    3    var d1 = db.Set<T_UserInfor>().Where(u => u.id == "01").FirstOrDefault();
    4    Console.WriteLine(db.Entry(d1).State);   //Unchanged
    5    var d2 = db.Set<T_UserInfor>().AsNoTracking().Where(u => u.id == "01").FirstOrDefault();
    6    Console.WriteLine(db.Entry(d2).State);   //Detached
    7  }

    二. 增加

    1. 原理

      修改实体到 Added 状态,调用 SaveChanges 时,生成 Insert 语句。

    2. 几种增加情况

      (1). 新建实体,然后 db.Set<T>().Add(u1); 或者 直接db.Add()方法,状态变化为:Detached→Added→Unchanged

      (2). 新建实体,直接修改状态 EntityState.Added,状态变化为:Detached→Added→Unchanged

     1                     {
     2                         var u1 = new T_UserInfor()
     3                         {
     4                             id = Guid.NewGuid().ToString("N"),
     5                             userName = "ypf",
     6                             userSex = "",
     7                             userAge = 19,
     8                             addTime = DateTime.Now
     9                         };
    10                         var u2 = new T_UserInfor()
    11                         {
    12                             id = Guid.NewGuid().ToString("N"),
    13                             userName = "ypf2",
    14                             userSex = "男2",
    15                             userAge = 19,
    16                             addTime = DateTime.Now
    17                         };
    18                         var state1 = db.Entry(u1).State;
    19                         var state2 = db.Entry(u2).State;
    20 
    21                         db.Set<T_UserInfor>().Add(u1);
    22                         db.Add(u2);
    23 
    24                         var state3 = db.Entry(u1).State;
    25                         var state4 = db.Entry(u2).State;
    26 
    27                         int count = db.SaveChanges();
    28 
    29                         var state5 = db.Entry(u1).State;
    30                         var state6 = db.Entry(u2).State;
    31 
    32                         Console.WriteLine($"count={count}");
    33                         Console.WriteLine($"{state1}→{state3}→{state5}");
    34                         Console.WriteLine($"{state2}→{state4}→{state6}");
    35                     }
    View Code
     1                     {
     2                         var u1 = new T_UserInfor()
     3                         {
     4                             id = Guid.NewGuid().ToString("N"),
     5                             userName = "ypf",
     6                             userSex = "",
     7                             userAge = 19,
     8                             addTime = DateTime.Now
     9                         };
    10                         var u2 = new T_UserInfor()
    11                         {
    12                             id = Guid.NewGuid().ToString("N"),
    13                             userName = "ypf2",
    14                             userSex = "男2",
    15                             userAge = 19,
    16                             addTime = DateTime.Now
    17                         };
    18                         var state1 = db.Entry(u1).State;
    19                         var state2 = db.Entry(u2).State;
    20 
    21                         db.Entry(u1).State = EntityState.Added;
    22                         db.Entry(u2).State = EntityState.Added;
    23 
    24                         var state3 = db.Entry(u1).State;
    25                         var state4 = db.Entry(u2).State;
    26 
    27                         int count = db.SaveChanges();
    28 
    29                         var state5 = db.Entry(u1).State;
    30                         var state6 = db.Entry(u2).State;
    31 
    32                         Console.WriteLine($"count={count}");
    33                         Console.WriteLine($"{state1}→{state3}→{state5}");
    34                         Console.WriteLine($"{state2}→{state4}→{state6}");
    35                     }
    View Code

    3. 批量增加

      调用AddRange方法,参数可以db.AddRange(u1, u2); 或者 db.AddRange(list); 批量增加最大的好处是生产一条sql语句,性能相对更高。

     1                     {
     2                         var u1 = new T_UserInfor()
     3                         {
     4                             id = Guid.NewGuid().ToString("N"),
     5                             userName = "ypf",
     6                             userSex = "",
     7                             userAge = 19,
     8                             addTime = DateTime.Now
     9                         };
    10                         var u2 = new T_UserInfor()
    11                         {
    12                             id = Guid.NewGuid().ToString("N"),
    13                             userName = "ypf2",
    14                             userSex = "男2",
    15                             userAge = 19,
    16                             addTime = DateTime.Now
    17                         };
    18                         var u3 = new T_UserInfor()
    19                         {
    20                             id = Guid.NewGuid().ToString("N"),
    21                             userName = "ypf",
    22                             userSex = "",
    23                             userAge = 19,
    24                             addTime = DateTime.Now
    25                         };
    26                         var u4 = new T_UserInfor()
    27                         {
    28                             id = Guid.NewGuid().ToString("N"),
    29                             userName = "ypf2",
    30                             userSex = "男2",
    31                             userAge = 19,
    32                             addTime = DateTime.Now
    33                         };
    34                         db.AddRange(u1, u2);
    35 
    36                         var list = new List<T_UserInfor>();
    37                         list.Add(u3);
    38                         list.Add(u4);
    39                         db.AddRange(list);
    40 
    41                         int count = db.SaveChanges();
    42                         Console.WriteLine($"count={count}");
    43 
    44                     }

    4. 指定自增键的插入

      通过ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] ON");先关闭自增,然后插入数据后,再通过ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] OFF");开启自增

     1                     try
     2                     {
     3                         db.Database.OpenConnection();
     4                         db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] ON");
     5                         var r2 = new T_RoleInfor()
     6                         {
     7                             id = 123,
     8                             roleName = "管理员",
     9                             roleDescription = "我是管理员"
    10                         };
    11                         db.Add(r2);
    12                         int count2 = db.SaveChanges();
    13                         db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] OFF");
    14                     }
    15                     catch (Exception)
    16                     {
    17                     }
    18                     finally
    19                     {
    20                         db.Database.CloseConnection();
    21                     }

    5. 调用SQL语句增加

      利用方法ExecuteSqlCommand("SQL增加语句")

    三. 修改

    1. 原理

      数据库中有主键所对应的记录,修改实体到 Modified 状态,调用 SaveChanges 时,生成 Update 语句。

    2. 几种更新情况

     (1).更新已经跟踪的实体(即从数据库中查询出来的),当修改值和数据库中不同时,状态变化为:Unchanged→Modified→Unchanged,直接执行SaveChanges方法执行修改。 当修改值和数据库中原值相同时,状态不发生变化:Unchanged→Unchanged→Unchanged,即使调用SaveChanges也不执行任何sql操作。

     1                     {
     2                         var u1 = db.T_UserInfor.Where(u => u.id == "01").FirstOrDefault();
     3                         var state1 = db.Entry(u1).State;
     4                         if (u1 != null)
     5                         {
     6                             u1.userName = "kkkk";
     7                         }
     8                         var state2 = db.Entry(u1).State;
     9                         int count = db.SaveChanges();
    10                         var state3 = db.Entry(u1).State;
    11                         Console.WriteLine($"count={count}");
    12                         Console.WriteLine($"{state1}→{state2}→{state3}");
    13                     }

     (2).更新未跟踪实体数据

     新建一个实体,这个实体必须有主键(且数据库中存在),未包含的属性则当做空值来更新,当修改值和数据库值不同时候,状态变化为: Detached→Modified→Unchanged。

     方案一:调用Update方法,其原理也是修改状态为 Modified。

     1                     {
     2                         var u1 = new T_UserInfor()
     3                         {
     4                             id = "01",
     5                             userName = "Marren",
     6                             addTime = DateTime.Now
     7                         };
     8                         var state1 = db.Entry(u1).State;
     9                         db.Update(u1);
    10                         //db.Set<T_UserInfor>().Update(u1);   //效果同上
    11                         var state2 = db.Entry(u1).State;
    12                         int count = db.SaveChanges();
    13                         var state3 = db.Entry(u1).State;
    14                         Console.WriteLine($"count={count}");
    15                         Console.WriteLine($"{state1}→{state2}→{state3}");
    16                     }

     方案二:直接修改状态 db.Entry(u1).State = EntityState.Modified;

     1                     {
     2                         var u1 = new T_UserInfor()
     3                         {
     4                             id = "01",
     5                             userName = "Marren",
     6                             addTime = DateTime.Now
     7                         };
     8                         var state1 = db.Entry(u1).State;
     9                         db.Entry(u1).State = EntityState.Modified;
    10                         var state2 = db.Entry(u1).State;
    11                         int count = db.SaveChanges();
    12                         var state3 = db.Entry(u1).State;
    13                         Console.WriteLine($"count={count}");
    14                         Console.WriteLine($"{state1}→{state2}→{state3}");
    15                     }

      特别注意:Update 方法 与 设置 EntityState 方案一样,会将实体状态设置为 Modified 状态。由于跟踪器没有任何方法来识别哪些属性值已经更改,所以生成的 UPDATE 语句会更新所有字段属性。Update 方法与显示设置设置 EntityState 不同的是,Update 方法会修改相关实体(如 Blog 的 Posts 导航属性)的状态为已修改,从而会为每个实体生成UPDATE语句。如果相关实体没有对应的键值,就会标记为 Added 状态,生成一条 Insert语句。

     方案三:Attach()用法。

     ①.新建一个实体,有主键(且数据库中存在、修改值和数据库值不同),调用Attach,状态变化 Detached→Unchanged→Unchanged ,未执行任何sql操作。

     ②.新建一个实体,有主键(且数据库中存在、修改值和数据库值不同),调用Attach,然后指定字段修改状态: db.Entry(u1).Property("userName").IsModified = true;状态变化为:Detached→Modified→Unchanged。 且只有userName这一个字段被修改

     ③. 该表主键是自增的,新建实体不设置主键,状态变化为:Detached→Addedd→Unchanged,执行了插入操作。

     1  //该主键在数据库中已经存在
     2                     //Detached→Unchanged→Unchanged(未执行任何sql操作)
     3                     {
     4                         var u1 = new T_UserInfor()
     5                         {
     6                             id = "01",
     7                             userName = "Marren1",
     8                             addTime = DateTime.Now
     9                         };
    10                         var state1 = db.Entry(u1).State;
    11                         db.Attach(u1);
    12                         var state2 = db.Entry(u1).State;
    13 
    14                         int count = db.SaveChanges();
    15 
    16                         var state3 = db.Entry(u1).State;
    17                         Console.WriteLine($"count={count}");
    18                         Console.WriteLine($"{state1}→{state2}→{state3}");
    19                     }
    20 
    21                     //该主键在数据库中已经存在
    22                      //Detached→Modified→Unchanged。 且只有userName这一个字段被修改
    23                     {
    24                         var u1 = new T_UserInfor()
    25                         {
    26                             id = "01",
    27                             userName = "Marren1",
    28                             addTime = DateTime.Now
    29                         };
    30                         var state1 = db.Entry(u1).State;
    31                         db.Attach(u1);
    32                         db.Entry(u1).Property("userName").IsModified = true;
    33                         var state2 = db.Entry(u1).State;
    34 
    35                         int count = db.SaveChanges();
    36 
    37                         var state3 = db.Entry(u1).State;
    38                         Console.WriteLine($"count={count}");
    39                         Console.WriteLine($"{state1}→{state2}→{state3}");
    40                     }
    41 
    42                     //该表主键是自增的,实体不设置主键
    43                      //Detached→Addedd→Unchanged。  (执行了插入操作)
    44                     {
    45                         var u1 = new T_RoleInfor()
    46                         {
    47                             roleName = "Marren1",
    48                             addTime = DateTime.Now
    49                         };
    50                         var state1 = db.Entry(u1).State;
    51                         db.Attach(u1);
    52                         var state2 = db.Entry(u1).State;
    53 
    54                         int count = db.SaveChanges();
    55 
    56                         var state3 = db.Entry(u1).State;
    57                         Console.WriteLine($"count={count}");
    58                         Console.WriteLine($"{state1}→{state2}→{state3}");
    59                     }
    View Code

    3. 调用SQL语句更新

      利用方法ExecuteSqlCommand("SQL更新语句")

    四. 删除

    1. 原理

     数据库中有主键所对应的记录,修改实体到 Deleted 状态,调用 SaveChanges 时,生成 Delete 语句。

    2. 删除已经跟踪的实体

     调用Remove方法或者直接设置EntityState.Deleted,状态变化为:Unchanged→Deleted→Detached

     注:查询出来的实体为空的话会报错。

     1                    //Unchanged→Deleted→Detached
     2                     //实体为空会报错
     3                     {
     4                         var u1 = db.T_UserInfor.Find("02");
     5                         var state1 = db.Entry(u1).State;
     6                         if (u1 != null)
     7                         {
     8                             db.Remove(u1);
     9                         }
    10                         var state2 = db.Entry(u1).State;
    11                         int count = db.SaveChanges();
    12                         var state3 = db.Entry(u1).State;
    13                         Console.WriteLine($"count={count}");
    14                         Console.WriteLine($"{state1}→{state2}→{state3}");
    15                     }
    16                     //Unchanged→Deleted→Detached
    17                     //实体为空会报错
    18                     {
    19                         var u1 = db.T_UserInfor.Find("03");
    20                         var state1 = db.Entry(u1).State;
    21                         if (u1 != null)
    22                         {
    23                             db.Entry(u1).State = EntityState.Deleted;
    24                         }
    25                         var state2 = db.Entry(u1).State;
    26                         int count = db.SaveChanges();
    27                         var state3 = db.Entry(u1).State;
    28                         Console.WriteLine($"count={count}");
    29                         Console.WriteLine($"{state1}→{state2}→{state3}");
    30                     }    

    3. 删除未跟踪的实体

     调用Remove方法或者直接设置EntityState.Deleted,状态变化为:Unchanged→Deleted→Detached

     注:如果数据库中不存在这个id,会报错

     1                    //Detached→Deleted→Detached
     2                     //如果数据库中不存在这个id,会报错
     3                     {
     4                         var u1 = new T_UserInfor() { id = "04" };
     5                         var state1 = db.Entry(u1).State;
     6                         db.Remove(u1);
     7                         var state2 = db.Entry(u1).State;
     8                         int count = db.SaveChanges();
     9                         var state3 = db.Entry(u1).State;
    10                         Console.WriteLine($"count={count}");
    11                         Console.WriteLine($"{state1}→{state2}→{state3}");
    12                     }
    13                  //Detached→Deleted→Detached
    14                     //如果数据库中不存在这个id,会报错
    15                     {
    16                         var u1 = new T_UserInfor() { id = "05" };
    17                         var state1 = db.Entry(u1).State;
    18                         db.Entry(u1).State = EntityState.Deleted;
    19                         var state2 = db.Entry(u1).State;
    20                         int count = db.SaveChanges();
    21                         var state3 = db.Entry(u1).State;
    22                         Console.WriteLine($"count={count}");
    23                         Console.WriteLine($"{state1}→{state2}→{state3}");
    24                     }        

    总结:无论是跟踪的实体还是未跟踪的实体,都可以调用Remove方法或者直接设置状态为 Deleted进行删除。(PS:与传统的EF不一样,不需要Attach)

    4. 批量删除或者调用SQL语句删除

     (1).批量删除:调用RemoveRange方法,生成一条SQL语句,性能相对更高。

    1                     {
    2                         var uList = db.T_UserInfor.Where(u => u.id != "01").ToList();
    3                         if (uList.Count() != 0)
    4                         {
    5                             db.RemoveRange(uList);
    6                         }
    7                         int count = db.SaveChanges();
    8                         Console.WriteLine($"count={count}");
    9                     }

     (2).调用SQL语句:利用方法ExecuteSqlCommand("SQL删除语句")

    5. 级联删除

     暂时用不到,后续补充。

     

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    MySQL进阶:主主复制+Keepalived高可用
    Zabbix 5.0:磁盘自动发现和读写监控
    Zabbix 5.0 优化建议
    容器进阶:OCI与容器运行时
    openresty快速安装
    ansible:playbook详解
    Shell:如何遍历包含空格的文本
    Linux性能优化:内存使用情况分析
    Shell:如何写一个多选菜单的脚本
    算法路漫漫(二) 递归与归并
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/11335401.html
Copyright © 2020-2023  润新知