第二节:EF Core的常规“增删改”及状态的变化
一. 整体说明
1. 本节用到的表
2. 状态说明补充
①.Detached: 游离的状态,与数据库没有什么交涉,比如新new一个实体,状态就是Detached。
②.Added: 增加的状态。
③.Deleted: 删除的状态。
④.Modified: 修改的状态。
⑤.Unchanged: 与数据库内容相比,未发生变化时的状态,从数据库中查询出来的对象就是Unchanged状态。
PS:查询出来的实体,AsNoTracking一下,就变成Detached游离状态了 。
using (DbContext db = new EFDB01Context())
{
var d1 = db.Set<T_UserInfor>().Where(u => u.id == "").FirstOrDefault();
Console.WriteLine(db.Entry(d1).State); //Unchanged
var d2 = db.Set<T_UserInfor>().AsNoTracking().Where(u => u.id == "").FirstOrDefault();
Console.WriteLine(db.Entry(d2).State); //Detached
}
二. 增加
1. 原理
修改实体到 Added 状态,调用 SaveChanges 时,生成 Insert 语句。
2. 几种增加情况
(1). 新建实体,然后 db.Set<T>().Add(u1); 或者 直接db.Add()方法,状态变化为:Detached→Added→Unchanged
(2). 新建实体,直接修改状态 EntityState.Added,状态变化为:Detached→Added→Unchanged
{
var u1 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf",
userSex = "男",
userAge = ,
addTime = DateTime.Now
};
var u2 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf2",
userSex = "男2",
userAge = ,
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
var state2 = db.Entry(u2).State; db.Set<T_UserInfor>().Add(u1);
db.Add(u2); var state3 = db.Entry(u1).State;
var state4 = db.Entry(u2).State; int count = db.SaveChanges(); var state5 = db.Entry(u1).State;
var state6 = db.Entry(u2).State; Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state3}→{state5}");
Console.WriteLine($"{state2}→{state4}→{state6}");
}
{
var u1 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf",
userSex = "男",
userAge = ,
addTime = DateTime.Now
};
var u2 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf2",
userSex = "男2",
userAge = ,
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
var state2 = db.Entry(u2).State; db.Entry(u1).State = EntityState.Added;
db.Entry(u2).State = EntityState.Added; var state3 = db.Entry(u1).State;
var state4 = db.Entry(u2).State; int count = db.SaveChanges(); var state5 = db.Entry(u1).State;
var state6 = db.Entry(u2).State; Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state3}→{state5}");
Console.WriteLine($"{state2}→{state4}→{state6}");
}
3. 批量增加
调用AddRange方法,参数可以db.AddRange(u1, u2); 或者 db.AddRange(list); 批量增加最大的好处是生产一条sql语句,性能相对更高。
{
var u1 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf",
userSex = "男",
userAge = ,
addTime = DateTime.Now
};
var u2 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf2",
userSex = "男2",
userAge = ,
addTime = DateTime.Now
};
var u3 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf",
userSex = "男",
userAge = ,
addTime = DateTime.Now
};
var u4 = new T_UserInfor()
{
id = Guid.NewGuid().ToString("N"),
userName = "ypf2",
userSex = "男2",
userAge = ,
addTime = DateTime.Now
};
db.AddRange(u1, u2); var list = new List<T_UserInfor>();
list.Add(u3);
list.Add(u4);
db.AddRange(list); int count = db.SaveChanges();
Console.WriteLine($"count={count}"); }
4. 指定自增键的插入
通过ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] ON");先关闭自增,然后插入数据后,再通过ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] OFF");开启自增
try
{
db.Database.OpenConnection();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] ON");
var r2 = new T_RoleInfor()
{
id = ,
roleName = "管理员",
roleDescription = "我是管理员"
};
db.Add(r2);
int count2 = db.SaveChanges();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] OFF");
}
catch (Exception)
{
}
finally
{
db.Database.CloseConnection();
}
5. 调用SQL语句增加
利用方法ExecuteSqlCommand("SQL增加语句")
三. 修改
1. 原理
数据库中有主键所对应的记录,修改实体到 Modified 状态,调用 SaveChanges 时,生成 Update 语句。
2. 几种更新情况
(1).更新已经跟踪的实体(即从数据库中查询出来的),当修改值和数据库中不同时,状态变化为:Unchanged→Modified→Unchanged,直接执行SaveChanges方法执行修改。 当修改值和数据库中原值相同时,状态不发生变化:Unchanged→Unchanged→Unchanged,即使调用SaveChanges也不执行任何sql操作。
{
var u1 = db.T_UserInfor.Where(u => u.id == "").FirstOrDefault();
var state1 = db.Entry(u1).State;
if (u1 != null)
{
u1.userName = "kkkk";
}
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
(2).更新未跟踪实体数据
新建一个实体,这个实体必须有主键(且数据库中存在),未包含的属性则当做空值来更新,当修改值和数据库值不同时候,状态变化为: Detached→Modified→Unchanged。
方案一:调用Update方法,其原理也是修改状态为 Modified。
{
var u1 = new T_UserInfor()
{
id = "",
userName = "Marren",
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
db.Update(u1);
//db.Set<T_UserInfor>().Update(u1); //效果同上
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
方案二:直接修改状态 db.Entry(u1).State = EntityState.Modified;
{
var u1 = new T_UserInfor()
{
id = "",
userName = "Marren",
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
db.Entry(u1).State = EntityState.Modified;
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
特别注意: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,执行了插入操作。
//该主键在数据库中已经存在
//Detached→Unchanged→Unchanged(未执行任何sql操作)
{
var u1 = new T_UserInfor()
{
id = "",
userName = "Marren1",
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
db.Attach(u1);
var state2 = db.Entry(u1).State; int count = db.SaveChanges(); var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
} //该主键在数据库中已经存在
//Detached→Modified→Unchanged。 且只有userName这一个字段被修改
{
var u1 = new T_UserInfor()
{
id = "",
userName = "Marren1",
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
db.Attach(u1);
db.Entry(u1).Property("userName").IsModified = true;
var state2 = db.Entry(u1).State; int count = db.SaveChanges(); var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
} //该表主键是自增的,实体不设置主键
//Detached→Addedd→Unchanged。 (执行了插入操作)
{
var u1 = new T_RoleInfor()
{
roleName = "Marren1",
addTime = DateTime.Now
};
var state1 = db.Entry(u1).State;
db.Attach(u1);
var state2 = db.Entry(u1).State; int count = db.SaveChanges(); var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
3. 调用SQL语句更新
利用方法ExecuteSqlCommand("SQL更新语句")
四. 删除
1. 原理
数据库中有主键所对应的记录,修改实体到 Deleted 状态,调用 SaveChanges 时,生成 Delete 语句。
2. 删除已经跟踪的实体
调用Remove方法或者直接设置EntityState.Deleted,状态变化为:Unchanged→Deleted→Detached
注:查询出来的实体为空的话会报错。
//Unchanged→Deleted→Detached
//实体为空会报错
{
var u1 = db.T_UserInfor.Find("");
var state1 = db.Entry(u1).State;
if (u1 != null)
{
db.Remove(u1);
}
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
//Unchanged→Deleted→Detached
//实体为空会报错
{
var u1 = db.T_UserInfor.Find("");
var state1 = db.Entry(u1).State;
if (u1 != null)
{
db.Entry(u1).State = EntityState.Deleted;
}
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
3. 删除未跟踪的实体
调用Remove方法或者直接设置EntityState.Deleted,状态变化为:Unchanged→Deleted→Detached
注:如果数据库中不存在这个id,会报错
//Detached→Deleted→Detached
//如果数据库中不存在这个id,会报错
{
var u1 = new T_UserInfor() { id = "" };
var state1 = db.Entry(u1).State;
db.Remove(u1);
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
//Detached→Deleted→Detached
//如果数据库中不存在这个id,会报错
{
var u1 = new T_UserInfor() { id = "" };
var state1 = db.Entry(u1).State;
db.Entry(u1).State = EntityState.Deleted;
var state2 = db.Entry(u1).State;
int count = db.SaveChanges();
var state3 = db.Entry(u1).State;
Console.WriteLine($"count={count}");
Console.WriteLine($"{state1}→{state2}→{state3}");
}
总结:无论是跟踪的实体还是未跟踪的实体,都可以调用Remove方法或者直接设置状态为 Deleted进行删除。(PS:与传统的EF不一样,不需要Attach)
4. 批量删除或者调用SQL语句删除
(1).批量删除:调用RemoveRange方法,生成一条SQL语句,性能相对更高。
{
var uList = db.T_UserInfor.Where(u => u.id != "").ToList();
if (uList.Count() != )
{
db.RemoveRange(uList);
}
int count = db.SaveChanges();
Console.WriteLine($"count={count}");
}
(2).调用SQL语句:利用方法ExecuteSqlCommand("SQL删除语句")
5. 级联删除
暂时用不到,后续补充。
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
最新文章
- Vim新手入门资料和一些Vim实用小技巧
- nrm NPM源管理工具
- UIView--震动效果
- URL特殊字符的转义
- HTML <;fieldset>; 标签将表单内的相关元素分组
- js中 map 遍历数组
- WebDriver运行异常列表
- How to hide an entry in the Add/Remove Programs applet?
- 关于PHP开发的9条建议
- C++线程类的封装
- 如何使用win7自带的备份还原以及创建系统镜像------傻瓜式教程
- Codeforces980 D. Perfect Groups
- Java Number &; Math 类
- sklearn中各种分类器回归器都适用于什么样的数据呢?
- RSA加密算法深入篇
- AirServer for Mac(Airplay 终端实用工具)破解版安装
- C# Monitor的Wait和Pulse方法使用详解
- 用IntelliJ的IDEA来创建SpringBoot框架
- c# 子窗体打开或者切换就最大化
- 20155331《网络对抗》Exp5 MSF基础应用
热门文章
- 二、NodeJS入门&mdash;&mdash;准备工作(2)&mdash;&mdash;MongoDB安装以及客户端Robomongo安装和使用
- html、css/bootStrap、js/Jquery、ajax与json数据交互总结
- Spark MLlib基本算法【相关性分析、卡方检验、总结器】
- Zabbix 添加内存告警
- Jmeter 使用自定义变量
- go处理XML
- selenium数据读取模块
- 排序算法-归并排序(Java)
- HTML基础一-html、CSS
- Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging