開發與維運

.NET 雲原生架構師訓練營(模塊二 基礎鞏固 EF Core 更新和遷移)–學習筆記

2.4.6 EF Core -- 更新

  • 狀態
  • 自動變更檢測
  • 不查詢刪除和更新
  • 併發

狀態

  • Entity State
  • Property State

Entity State

  • Added 添加
  • Unchanged 沒有變化
  • Modified 已修改
  • Deleted 已刪除
  • Detached 未跟蹤

35.jpg

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

Leave a Reply

Your email address will not be published. Required fields are marked *