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) 。