前言
初识EF操作数据库,虽然看了资料会用但是有些懵懂,闲下来仔细了解,才算真正懂得这是怎么一回事。
r(查找)比较简单,就不再多说。
正文
DbContext:一个数据上下文
我们在EF中实例化一个继承自DbContext的上下文,这个上下文包含很多DbSet成员。我想说的是,对于同一个上下文,当其交使用SavaChanged方法互数据库时会把所有操作包含在一个事务内,事务的作用就是为了保证所有sql执行成功的,不成功则回滚。所以你在执行多个操作时大可放心不全部成功执行的问题。如:
db.UserInfo.Add(user);
db.User.Add(user);
db.SaveChanges();
这里我有一个需求:当用户注册时向两个表中插入数据,一个是用户基本信息表一个是用户的具体信息表。必须同时插入成功,不能出现一个表成功插入另一个表失败的情况,这个时候放心使用SavaChanged吧。
SavaChanged():一个数据提交方式
SavaChanged()用于提交数据。db.SavaChanged()返回值是数据库中有几条数据被影响,所以你可以用db.SavaChanged()>0来判断是否成功的插入、修改、删除了数据。
EntityState:5个状态值
当SavaChanged()方法执行期间,他会查看当前Entity的EntityState的值,决定是去新增(Added)、修改(Modified)、删除(Deleted)、什么也不做。
如:
db.Entry(userinfo).State = EntityState.Added;
打开EntityState
Detached,当前实体没有存在于dbContext(数据库)中
Unchanged,当前实体属性值没有发生改变
Added,标记为增加状态,下次saveChange将添加到数据库中
Deleted,标记删除状态,下次saveChange将删除
Modified,标记为更改状态,下次将更新
对于Detached:
UserInfo userinfo = new UserInfo();
EntityState userinfoState2 = db.Entry(userinfo).State;
这里userinfo 和db没有任何关系,所以userinfoState2值是Detached。
3个EF方法
Attach是连接,可以看成从数据库读取出了实体(但没有操作数据库)
Add,其实也就是将实体状态改为added。
remove,所操作的实体不能是Detached状态(也就是说实体必须存在于db中)
对于Attach:
Attach,执行下面代码看下数据库sql语句:
UserInfo userinfo6 = new UserInfo();
userinfo6.ID = 4;
db.UserInfo.Attach(userinfo6);
Console.WriteLine(db.Entry(userinfo6).State);
数据库监视器并没有监视到sql,所以Attach是不操作数据库的。当savechange时才会操作生成sql交互数据库。
注意:Attach后的实体状态是Unchanged。当你想要修改(modified)和删除(remove)数据,必须修改实体状态。
CUD操作
增加
// 第一种方式,建议使用
UserInfo userinfo=new UserInfo(){ Name="苏轼"};
db.UserInfo.Add(userinfo);
db.SavaChanged();
// 第二种方式:设置状态state
db.Entry(userinfo).State = EntityState.Added;
db.SavaChanged();
注意:SavaChanged()时会进行数据回调,以便你在进行增加(或修改)后可以马上取到数据进行使用。假如你数据库的id是自增的,上面增加成功后userinfo的id就被赋予了数据库的值。这是很有用的,比如用户上传了文件后要返回文件id的情境。
修改
// 先查再改,数据库操作两次,不建议
UserInfo userinfo = db.UserInfo.FirstOrDefault(u => u.ID == 1);
userinfo.Name = "苏轼";
db.SavaChanged();
// 第二种方式,使用Attach,数据库操作一次,建议
UserInfo userinfo = new UserInfo() { ID = 1,Name = "苏轼" };
db.UserInfo.Attach(userinfo);
db.SavaChanged();
// 第三种,直接设置实体状态,数据库操作一次,建议
UserInfo userinfo4 = new UserInfo(){ ID = 1,Name = "苏轼" };
db.Entry(userinfo4).State = System.Data.Entity.EntityState.Modified;
db.SavaChanged();
上面几种都会修改实体的所有字段并不灵活,有时候需求是只需要修改其中一两个字段而已,怎么办呢?我们可以分别设置字段的IsModified值来控制字段是否是可修改的。以Attach方式为例:
UserInfo userinfo = new UserInfo() { ID = 1,Name = "苏轼" };
db.UserInfo.Attach(userinfo);
db.Entry(userinfo4).Property("Sex").IsModified = false;
db.Entry(userinfo4).Property("Name").IsModified = true;
// 这里我们还可以使用lambda
db.Entry(model).Property(u => u.Status).IsModified = false;
db.SavaChanged();
上面的代码,不会修改Sex、Name、Status的值,这种方式对于避免了不必要的字段修改。
删除
// 第一种,remove
db.UserInfo.Attach(userinfo6);
db.UserInfo.Remove(userinfo6);
db.SavaChanged();
// 第二种,设置状态
db.Entry(userinfo6).State = EntityState.Deleted;
db.SavaChanged();
// 第三种,先查出来再改,这是微软推荐方法,因为上两种,不管附加还是设置状态,数据库不存在这个实体程序就会报错
UserInfo userinfo6 = db.UserInfo.FirstOrDefault(u => u.ID == 1);
if (userinfo6 != null)
db.UserInfo.Remove(userinfo6);
当你如果你确定这个数据在数据库中存在,用前两种方式的确是最好的,假如你进行了异常检测如使用了try-catch,也可以使用前两种
总结
- 同一个DbContext上下文操作中使用事务保证操作完整性。
- 使用SavaChanged进行数据提交
- 数据提交时是根据实体(或者说是字段)的EntityState状态来进行相应的增加、删除、修改操作的。可以直接修改其状态,也可以通过Add、Attach、Remove修改其状态