发布:2023/12/7 15:44:17作者:大数据 来源:大数据 浏览次数:542
efcore和.netcore更新部分字段,或更新部分列数据,update操作网上说的千奇百怪,有的根本不能执行,所以在此,进行了总结,欢迎大家参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public ActionResult Edit(int id) { var q = dbContext.LeaveRecord.Find(id); if (q == null) { return NotFound(); } return View(q); } // POST: LeaveController/Edit/5, [ValidateAntiForgeryToken] public async Task<ActionResult> EditAsync(int? id) { if (id ==null) { return NotFound(); } if (ModelState.IsValid) { try { var q = dbContext.LeaveRecord.Find(id); if (await TryUpdateModelAsync(q, "", o => o.PersonName, o => o.LeaveType, o => o.Sex)) { await dbContext.SaveChangesAsync(); } } catch { return View(); } return RedirectToAction(nameof(Index)); } return View(); } |
此方法首先查询出实体数据,然后根据lambda表达式中的字段进行更新对应的实体字段,注意lambda表达式,都为这样的参数格式o=>o.x1,o=>o.x2而不是o=>o.x1,o.x2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// GET: LeaveController/Edit/5 public ActionResult Edit(int id) { var q = dbContext.LeaveRecord.Find(id); if (q == null) { return NotFound(); } return View(q); } // POST: LeaveController/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public ActionResult EditAsync(int? id, LeaveRecord leaveRecord) { if (id ==null) { return NotFound(); } if (ModelState.IsValid) { try { var q = dbContext.LeaveRecord.Find(id); q.PersonName = leaveRecord.PersonName; q.Sex = leaveRecord.Sex; q.LeaveType = leaveRecord.LeaveType; q.LeaveReason = leaveRecord.LeaveReason; dbContext.Update(q); dbContext.SaveChanges(); } catch { return View(); } return RedirectToAction(nameof(Index)); } return View(); } |
view视图文件
1 2 |
<input type="text" readonly asp-for="Title" /> <input type="text" asp-for="Content" /> |
假设只更新content字段数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// GET: UserController/Edit/5 public ActionResult Edit(int id) { var q = dbContext.User.Find(id); return View(q); } // POST: UserController/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(int id, User user) { try { dbContext.Attach(user); //将需要更新的字段设置为true,没有设置的字段不更新,这种方法不用查询数据库找到实体 dbContext.Entry(user).Property(o => o.UserName).IsModified = true; dbContext.SaveChanges(); return RedirectToAction(nameof(Index)); } catch(Exception ex) { return View(); } } |
但如果需要更新的列多的话,会照样写成很多类似语句:
1 |
dbContext.Entry(user).Property(o => o.UserName).IsModified = true; |
1 |
dbContext.Entry(user).Property(o => o.UserPassword).IsModified = true; |
当然这样的语句可以用循环的方式实现,将需要更新的字段封装起来,然后通过循环遍历设置为true,以下代码可以参考
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public void UpdateEntityFields(T entity, List<string> fileds) { if (entity != null&&fileds!=null) { dbContext.CreateObjectSet<T>().Attach(entity); var SetEntry = ((IObjectContextAdapter)dbContext).ObjectContext. ObjectStateManager.GetObjectStateEntry(entity); foreach (var t in fileds) { SetEntry.SetModifiedProperty(t); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// GET: UserController/Edit/5 public ActionResult Edit(int id) { var q = dbContext.User.Find(id); return View(q); } // POST: UserController/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(int id, User user) { try { var d = dbContext.Attach(user); dbContext.Entry(user).State = EntityState.Modified;//将所有字段设置为要更新的状态 dbContext.Entry(user).Property(o=>o.UserName).IsModified = false;//再将不需要的字段设置为不更新,那么这样就达到了更新多个字段,除此字段外 dbContext.SaveChanges(); return RedirectToAction(nameof(Index)); } catch (Exception ex) { return View(); } } |
注意:加了Attach在SaveChanges()前面一定不要再加dbContext.Update(user);加上此句会出错,导致上面的设置状态无效,会全部更新,所以一定不要加。
dbContext.Database.ExecuteSqlRaw("sql语句",参数1值, 参数2值,...);
1 2 3 4 5 6 7 8 9 10 11 12 |
public ActionResult Edit(int id, User user) { try { dbContext.Database.ExecuteSqlRaw($"update User set userName='{user.UserName}',userpassword='{user.UserPassword}' where id={user.Id}"); return RedirectToAction(nameof(Index)); } catch (Exception ex) { return View(); } } |
警告
始终对原始 SQL 查询使用参数化
向原始 SQL 查询引入任何用户提供的值时,必须注意防范 SQL 注入攻击。 除了验证确保此类值不包含无效字符,请始终使用会将值与 SQL 文本分开发送的参数化处理。
具体而言,如果连接和内插的字符串 ($""
) 带有用户提供的未经验证的值,则切勿将其传递到 FromSqlRaw
或 ExecuteSqlRaw
。 通过 FromSqlInterpolated
和 ExecuteSqlInterpolated
方法,可采用一种能抵御 SQL 注入攻击的方式使用字符串内插语法。一般这种方法用于内部确定的更新操作。比如将某个字段更新为某个值等。
以上方法必须保证参数值是经过处理的,否则不建议用$""这样的形式。下面的两个方法进行参数化防止sql注入攻击:
1 |
dbContext.Database.ExecuteSqlRaw("update User set userName={0},userpassword={1} where id={2}","user01","123123",3);//将id=3的user用户名和密码进行更新 |
这里是mysql用 MySqlParameter,sql用SqlParameter,注意对应关系否则出错,代码如下:
1 2 3 4 5 |
int id=3; dbContext.Database.ExecuteSqlRaw("update User set userName=@userName,userpassword=@password where id=@id", new MySqlParameter("@userName", "jone"), new MySqlParameter("@password", "12345"), new MySqlParameter("@id",id)); |
上面使用的参数化赋值,参数可与字段名不同,可以参考对比。
FromSqlRaw只用作查询。
params object[] parameters或params object[] args作为方法参数时,指明该参数为可变长度和类型参数,比如“abc",1,true可传入。
前面几种方法根据具体情况使用即可。
经常见类似这样的[bind("")] User user,为什么要绑定对应字段呢,主要是为了防止过度发布,比如User实体中有3个字段,分别 为id,username,userpassword,在进行更新Edit操作时,虽然表单里对应的只id,name两个input,但下面的代码user对象里是3个字段,黑客会利用工具将userpassword字段什传入了,导致更新时把密码也修改了!
1 2 3 4 |
// POST: UserController/Edit/5 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(int id,[Bind("id,username")] User user) |
微软官方实例如下图:
防止以上过度发布可以使用Bind属性来绑定需要更新的字段,其它字段即可传送过来也会清空,但这样在更新数据时不能直接dbcontext.update(user)然后进行savechanges()提交。只能查询到的user实体,再将参数中user赋值到需要更新的字段,当然还有更好的办法是使用上面提到的,
1 |
dbContext.Entry(user).Property(o => o.UserName).IsModified = true; |
将需要更新的字段更新,这种方法不需要进行查询,直接使用的user实体。
参考资料:
EntityState的5个状态解释:
成员名称 | 说明 |
---|---|
Detached | 对象存在,但没有被跟踪。 在创建实体之后、但将其添加到对象上下文之前,该实体处于此状态。 An entity is also in this state after it has been removed from the context by calling the Detach method or if it is loaded by using a NoTrackingMergeOption. 没有 ObjectStateEntry 实例与状态为 Detached 的对象关联。 |
Unchanged | 自对象附加到上下文中后,或自上次调用 SaveChanges 方法后,此对象尚未经过修改。 |
Added | 对象为新对象,并且已添加到对象上下文,但尚未调用 SaveChanges 方法。 在保存更改后,对象状态将更改为 Unchanged。 状态为 Added 的对象在 ObjectStateEntry 中没有原始值。 |
Deleted | 对象已从对象上下文中删除。 在保存更改后,对象状态将更改为 Detached。 |
Modified | 对象上的一个标量属性已更改,但尚未调用 SaveChanges 方法。 在不带更改跟踪代理的 POCO 实体中,调用 DetectChanges 方法时,已修改属性的状态将更改为 Modified。 在保存更改后,对象状态将更改为 Unchanged。 |
https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.entityframeworkcore.entitystate?view=efcore-5.0#Microsoft_EntityFrameworkCore_EntityState_Modified
上下文正在跟踪实体的状态。
C#
1 |
public enum EntityState |
继承
EntityState
Added | 4 | 实体正在由上下文跟踪,但数据库中尚不存在。 |
Deleted | 2 | 实体正在由上下文跟踪,并存在于数据库中。 已将其标记为从数据库中删除。 |
Detached | 0 | 上下文未跟踪该实体。 |
Modified | 3 | 实体正在由上下文跟踪,并存在于数据库中。 已经修改了其部分或全部属性值。 |
Unchanged | 1 | 实体正在由上下文跟踪,并存在于数据库中。 不会更改数据库中的值的属性值。 |
产品 | 版本 |
---|---|
Entity Framework Core | 1.0, 1.1, 2.0, 2.1, 2.2, 3.0, 3.1, 5.0 |
© Copyright 2014 - 2025 柏港建站平台 ejk5.com. 渝ICP备16000791号-4