2.4.6 EF Core -- 更新

  • 状态
  • 自动变更检测
  • 不查询删除和更新
  • 并发

状态

  • Entity State
  • Property State

Entity State

  • Added 添加
  • Unchanged 没有变化
  • Modified 已修改
  • Deleted 已删除
  • Detached 未跟踪

Property State

  • IsModified
  • CurrentValue
  • OriginValue

自动变更检测

  • 使用自动变更检测完成确定字段的更新
  • 使用自动变更检测完成任意字段的更新

使用自动变更检测完成确定字段的更新

ProjectController

[HttpPatch]
[Route("{id}")]
public async Task<ActionResult<Project>> SetTitleAsync(string id, [FromQuery] string title, CancellationToken cancellationToken)
{
// 查询实体信息
var origin = await _lighterDbContext.Projects.FirstOrDefaultAsync(p => p.Id == id, cancellationToken); // 修改实体属性
origin.Title = title; // 数据提交保存
await _lighterDbContext.SaveChangesAsync(); return origin;
}

修改分组信息

// 查询实体信息
var originGroup = await _lighterDbContext.ProjectGroups.Where(g => g.ProjectId == id).ToListAsync(cancellationToken: cancellationToken); // 修改实体属性
foreach (var group in originGroup)
{
group.Name = $"{title} - {group.Name}";
}

查询项目信息时带出分组信息

[HttpGet]
public async Task<IEnumerable<Project>> GetListAsync(CancellationToken cancellationToken)
{
return await _lighterDbContext.Projects.Include(p => p.Groups).ToListAsync(cancellationToken);
}

使用自动变更检测完成任意字段的更新

[HttpPatch]
[Route("{id}")]
public async Task<ActionResult<Project>> SetAsync(string id, CancellationToken cancellationToken)
{
// 查询实体信息
var origin = await _lighterDbContext.Projects.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
var properties = _lighterDbContext.Entry(origin).Properties.ToList(); // 修改实体属性
foreach (var query in HttpContext.Request.Query)
{
var property = properties.FirstOrDefault(p => p.Metadata.Name == query.Key);
if (property == null)
continue; var currentValue = Convert.ChangeType(query.Value.First(), property.Metadata.ClrType); _lighterDbContext.Entry(origin).Property(query.Key).CurrentValue = currentValue;
_lighterDbContext.Entry(origin).Property(query.Key).IsModified = true;
} // 数据提交保存
await _lighterDbContext.SaveChangesAsync(cancellationToken); return origin;
}

不查询删除和更新

删除之前先查询

var id = 1;
using(var db = new entityContext())
{
var entity = db.dbset.FirstOrDefault(e=>e.ID == id);
if(entity != null)
{
db.dbset.Remove(entity);
db.SaveChanges();
}
}

不查询删除

var id = 1;
using(var db = new entityContext())
{
var entity = new Entity{ID = id}; db.dbset.Attach(entity);
db.dbset.Remove(entity);
db.SaveChanges();
}

不查询更新

try
{
using(var db = new dbContext())
{
var entity = new myEntity{PageID = pageid};
db.Pages.Attach(entity);// added entity.Title = "new title";// modified, isModified=true
entity.Url = "new-url"; db.SaveChanges();
}
}
catch(DataException)
{ }

并发

乐观处理:系统认为数据的更新在大多数情况下是不会产生冲突的,只在数据库更新操作提交的时候才对数据作冲突检测(推荐)

悲观处理:根据命名即对数据库进行操作更新时,对操作持悲观保守的态度,认为产生数据冲突的可能性很大,需要先对请求的数据加锁再进行相关操作

在 Entity 中添加行版本号字段

/// <summary>
/// 行版本号
/// </summary>
[Timestamp]
public byte[] RowVersion { get; set; }

每次对数据进行更新的时候,都会产生最新的版本号,如果更新的时候查询的版本号与之前的版本号不一致,就会报错

在 UpdateAsync 方法中的查询和更新中间如果数据库的行版本号发生了修改,就会报错

ProjectController

[HttpPut]
[Route("{id")]
public async Task<ActionResult<Project>> UpdateAsync(string id, [FromBody] Project project, CancellationToken cancellationToken)
{
var origin = await _lighterDbContext.Projects.FirstOrDefaultAsync(p => p.Id == id, cancellationToken); if (origin == null)
return NotFound(); _lighterDbContext.Entry(origin).CurrentValues.SetValues(project); await _lighterDbContext.SaveChangesAsync(cancellationToken);
return origin;
}

通过客户端传入行版本号,解决前端浏览器数据覆盖问题

_lighterDbContext.Entry(origin).Property(p => p.RowVersion).OriginalValue = project.RowVersion;

2.4.7 EF Core -- 迁移

生成 SQL 脚本

从空白开始生成sql脚本
dotnet ef migrations script 生成指定版本到最新版本的sql
dotnet ef migrations script AddNewTables 从A-B版本生成迁移SQL脚本
dotnet ef migrations script AddNewTables AddAuditTable

2.4.8 EF Core -- 其他

database-first

dotnet ef dbcontext scaffold "server=172.0.0.1;port=7306;user=root;password=root123456@;database=lighter" Pomelo.EntityFrameworkCore.MySql -o Models

GitHub源码链接:

https://github.com/MINGSON666/Personal-Learning-Library/tree/main/ArchitectTrainingCamp/LighterApi

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

.NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记的更多相关文章

  1. .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记

    目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...

  2. .NET 云原生架构师训练营(建立系统观)--学习笔记

    目录 目标 ASP .NET Core 什么是系统 什么是系统思维 系统分解 什么是复杂系统 作业 目标 通过整体定义去认识系统 通过分解去简化对系统的认识 ASP .NET Core ASP .NE ...

  3. .NET 云原生架构师训练营(权限系统 RGCA 架构设计)--学习笔记

    目录 项目核心内容 实战目标 RGCA 四步架构法 项目核心内容 无代码埋点实现对所有 API Action 访问控制管理 对 EF Core 实体新增.删除.字段级读写控制管理 与 Identity ...

  4. .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记

    2.7.1 敏捷开发 敏捷介绍 敏捷的起源 敏捷软件开发宣言 敏捷开发十二原则 生命周期对比 敏捷开发的特点 敏捷的发展 敏捷的核心 敏捷的起源 2001年,17个老头子在一起一边滑雪,一边讨论工作, ...

  5. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 介绍和基础)--学习笔记

    2.5.1 MongoDB -- 介绍 mysql vs mongo 快速开始 mysql vs mongo 对比 mysql mongo 数据存储 table 二维表结构,需要预先定义结构 json ...

  6. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 问答系统)--学习笔记

    2.5.6 MongoDB -- 问答系统 MongoDB 数据库设计 API 实现概述 MongoDB 数据库设计 设计优化 内嵌(mongo)还是引用(mysql) 数据一致性 范式:将数据分散到 ...

  7. .NET 云原生架构师训练营(模块二 基础巩固 Scrum 团队)--学习笔记

    2.7.3 Scrum 团队 理想的环境 团队章程 如何组建 Scrum 团队 产品待办事项列表 用户故事 敏捷开发流程 理想的环境 5-9人 100% 跨职能 在一起 自组织 自组织 目标 授权 沟 ...

  8. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 写入和查询)--学习笔记

    2.5.3 MongoDB -- 写入和查询 写入 查询 查找操作符 逻辑操作符 其他 嵌套对象 数组 游标方法 写入 https://docs.mongodb.com/manual/tutorial ...

  9. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 更新和删除)--学习笔记

    2.5.4 MongoDB -- 更新和删除 整体更新 更新字段 字段操作 数组操作 删除 https://docs.mongodb.com/manual/reference/operator/upd ...

随机推荐

  1. JZOJ 2020.10.6 提高B组反思

    JZOJ 2020.10.6 提高B组反思 T1 NYG的动态数点 最简单的一题 很容易想到\(O(n)\)的做法 枚举最小的那个数,即\(a_k\) 然后向左和向右扩展 然后可以直接从右端点+1继续 ...

  2. 【C++】“反转链表”相关的题目

    1.反转链表:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点. (1)这道题是经典的题目了,用迭代的方式解决也是很容易的,代码量也不大.分享一个我个人做题的方式,我会先在题目开 ...

  3. iNeuOS工业互联平台,WEB组态(iNeuView)图元和数据点组合及生成新图元复用,实现拖业务

    目       录 1.      概述... 1 2.      平台演示... 2 3.      应用过程... 2 1.   概述 iNeuView视图建模Web组态平台实现图元和数据点组合及 ...

  4. 第4.3节 Python中与迭代相关的函数

    下面要介绍的enumerate.range.zip.reversed.sorted属于Python内置的函数或者类别,返回的对象都可通过迭代方法访问. 一.    enumerate函数 1.     ...

  5. PyQt(Python+Qt)学习随笔:QMainWindow的tabifyDockWidget方法将QDockWidget两个停靠窗选项卡式排列

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 主窗口的tabifyDockWidget方法用于将主窗口的两个停靠窗口 ...

  6. PyQt(Python+Qt)学习随笔:QListWidget获取指定项对应行的row方法

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListWidget的row方法通过项作为参数,获取到对应项所在行的行号,语法如下: int ro ...

  7. PyQt学习随笔:截获窗口Widget组件的关闭事件

    在PyQt中,QWidget类对应基础的窗口组件,如果要在窗口组件关闭时截获关闭事件,提供自己的控制机制,则可以通过在自定义的派生类中重写closeEvent方法. 重写closeEvent方法的语法 ...

  8. PyQt(Python+Qt)学习随笔:窗口的布局设置及访问

    老猿Python博文目录 老猿Python博客地址 在Qt Designer中,可以在一个窗体上拖拽左边的布局部件,在窗口中进行布局管理,但除了基于窗体之上进行布局之外,还需要窗体本身也进行布局管理才 ...

  9. autojs websocket 核心示例代码,云控技术

    //初始化方法 function recordInit(scriptName){ //let ipInfoJson = getIP() // let ip = ipInfoJson.cip // le ...

  10. Docker 命令自动补全?要的

    前言 不知道这个小伙伴有多久没用过 Docker 了, 突然对我说 Docker 命令怎么发生变化了 docker run ... #变成了 docker container run ... 他说,本 ...