关于EntityFramework 更新数据记录时字段全部更新问题和不从数据库中获取直接更新记录
一、一直对这个比较疑惑感觉只修改一条数据记录的一个字段结果更新Savechages后跟踪生成sql竟然是全部被修改,感觉微软怎么这么傻,总觉得会有其它方式可以只更新部分字段,但一直没有找到相关设置,最近看DbContext相关内容发现是可以只更新部分字段,原来一直的操作方式是有问题下面粘代码详细说明。
1、首先看全部更新字段情况
[TestMethod] public void UpdateCustomer() { //Customer customer3 = new Customer(); //customer3.Id = 22; //customer3.CustName = DateTime.Now.ToString("yyMMddHHmmssff"); //customer3.CustAddress = "北京25"; CustoemrRepository cuR = new CustoemrRepository(); Customer cuM = cuR.GetEntities(x => x.Id == 22).FirstOrDefault(); cuM.CustAddress = "北京0614"; int row = cuR.UpdateModel(cuM); }
/// <summary> /// 修改实体对象 /// </summary> /// <param name="model"></param> /// <returns></returns> public int UpdateModel(TEntity model) { //if (unDbContext.Entry<TEntity>(model).State == System.Data.Entity.EntityState.Detached) //{ // unDbContext.Entry(model).State = EntityState.Modified; //} unDbContext.Entry(model).State = EntityState.Modified; return unDbContext.SaveChanges(); }
这种修改方式生成的sql是
exec sp_executesql N'UPDATE [dbo].[Customer] SET [CustName] = @0, [CustCode] = NULL, [CustAddress] = @1 WHERE ([Id] = @2) ',N'@0 nvarchar(max) ,@1 nvarchar(max) ,@2 int',@0=N'17061409012697',@1=N'北京0614',@2=22
将Cutomer记录的全部字段更新了
如果将更新方式换做这样写
/// <summary> /// 修改实体对象 /// </summary> /// <param name="model"></param> /// <returns></returns> public int UpdateModel(TEntity model) { if (unDbContext.Entry<TEntity>(model).State == System.Data.Entity.EntityState.Detached) { unDbContext.Entry(model).State = EntityState.Modified; } return unDbContext.SaveChanges(); }
生成sql为
exec sp_executesql N'UPDATE [dbo].[Customer] SET [CustAddress] = @0 WHERE ([Id] = @1) ',N'@0 nvarchar(max) ,@1 int',@0=N'北京0614',@1=22
可以看出这样只更新了 CustAddress 这个字段其它字段没有更新,这是因为 这句代码 unDbContext.Entry(model).State = EntityState.Modified; 没有执行,因为该数据记录是从数库中取出来的所以你修改记录相应字段后Entityframework会自动跟踪
修改字段 直接 unDbContext.SaveChanges(); 就可以将修改记录保存到数据库,且只更新修改字段。 所以从数据库中取的数据记录“ unDbContext.Entry(model).State = EntityState.Modified;”这句不需要。
下面说一下这句
unDbContext.Entry(model).State = EntityState.Modified;
将其状态设为 EntityState.Modified 是针对要保存的实体对象不是从数据库中取出,而是在代码中 自己New的对象不是从数据库中取出来的,这时候需要
unDbContext.Entry(model).State = EntityState.Modified; 将其状态修改且Dbcontext为对它有相应修改处理,如果不设置对象将不在Dbcontext中会报错。
二、下面说一下怎样自己实例化的对象 不从数据库中取 然后更新数据记录,这样减少了一次数据库获取数据会提高相应效率,当然不太要求性能的系统中还是从数据库中取比较简单,下面做了一个简单实现大家感兴趣可以详细扩展。
[TestMethod] public void UpdateCustomer() { // 自己实例化要更新对象 省了访问数据库获取数据时间 Customer customer3 = new Customer(); customer3.Id = 22; customer3.CustAddress = "北京25"; List<string> listRmoveFiled = new List<string>(); listRmoveFiled = "CustCode,CustName".Split(',').ToList<string>(); CustoemrRepository cuR = new CustoemrRepository(); int row = cuR.UpdateModel(customer3,listRmoveFiled); }
具体实现部分简单处理(大家可以写的风骚,精湛些)
/// <summary> /// 修改实体对象 /// </summary> /// <param name="model"></param> /// <returns></returns> public int UpdateModel(TEntity model, List<string> listRemoveField = null) { // 排除不需更新的字段 foreach (string field in listRemoveField) { if (field != "Id") unDbContext.Entry(model).Property(field).IsModified = false; } if (unDbContext.Entry<TEntity>(model).State == System.Data.Entity.EntityState.Detached) { //将model追加到EF容器 unDbContext.Entry(model).State = EntityState.Modified; } return unDbContext.SaveChanges(); }
这样处理就可以省了从数据库中获取再修改,自己直接实例化更新部分字段就可以直接更新到数据库中。写到这里对这一块的整理也就结束了。