簡體   English   中英

如何更新 Entity Framework Core 中的單個屬性

[英]How to update a single property in Entity Framework Core

我只需要更新實體的一兩個屬性。 換句話說,我有一個帶有 Id、ParentId、Name 和 Description 的實體。

問題是當名稱更新時,如果描述已經存在於數據庫中,它就會被清除。

這是代碼:

internal void Update(ItemInfo itemInfo)
{
    var item = new Item { Id = itemInfo.Id, ParentId = itemInfo.ParentId, Name = itemInfo.Name };
    var entry = this.DbContext.Items.Attach(item);
    if (item.ParentId != null) entry.Property(x => x.ParentId).IsModified = true;
    if (!(String.IsNullOrWhiteSpace(item.Name))) entry.Property(x => x.Name).IsModified = true;
    this.SaveChanges();;
}

我認為由於我將特定屬性設置為已修改,因此只會更新該屬性。

或者我應該首先從數據庫中獲取實體,然后只設置屬性並保存。 我想避免一次保存兩次訪問數據庫。

您可以執行以下操作以更新單個屬性:

internal void Update(ItemInfo itemInfo)
{
    if (itemInfo == null) { throw new Exception($"item info was not supplied"); }

    var itemInfoEntity = new ItemInfo()
    {
        Id          = itemInfo.Id,
        ParentId    = itemInfo.ParentId,
        Name        = itemInfo.Name 
    };

    dbContext.ItemInfo.Attach(itemInfoEntity);
    dbContext.Entry(itemInfoEntity).Property(x => x.Id).IsModified = true;
    dbContext.Entry(itemInfoEntity).Property(x => x.Id).IsModified = true;
    dbContext.Entry(itemInfoEntity).Property(x => x.Id).IsModified = true;
    dbContext.SaveChanges();
}

但是如果你只更新幾個屬性,那么我認為你不應該將整個對象作為參數發送,只需發送需要更新的屬性,如下所示:

internal void Update(id, parentId, name)
{
 ...
}

您真正追求的是並發處理。 當多個用戶同時編輯同一個對象時,第二個用戶將覆蓋第一個用戶的更改。

或者我應該首先從數據庫中獲取實體,然后只設置屬性並保存。

是的,但是為對象的每個屬性都設置一個控制器方法會非常乏味。 這就是為什么並發處理是最好的選擇。

此外,您的域模型應該與您的數據庫模型完全分開。 切勿直接在 Web 應用程序中使用實體。 您已經通過使用Item實體(數據庫模型)和ItemInfo類(域模型,用於處理后請求)來實現這一點。

實現並發處理

首先向您的實體添加Timestamp列:

internal class Item
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
    
    [Timestamp]
    [ConcurrencyCheck]
    public byte[] ConcurrencyStamp { get; set; }
}

然后,在您更新實體的地方:

[Controller]
public class ItemController : Controller
{
    private readonly DbContext dbContext;
    public ItemController(DbContext dbContext)
    {
        this.dbContext = dbContext;
    }
    
    [HttpPost]
    //[Authorize]
    //[ValidateAntiForgeryToken]
    public async Task<ActionResult<ItemInfo>> Update([FromBody] ItemInfo item)
    {
        var existingItem = dbContext.Items.SingleOrDefaultAsync(i => i.Id == item.Id);
        if (Convert.ToBase64String(existingItem.ConcurrencyStamp) != item.ConcurrencyStamp)
        {
            var databaseValue = new ItemInfo
            {
                Id = existingItem.Id,
                ParentId = existingItem.ParentId,
                Name = existingItem.Name,
            };
            return StatusCode(Microsoft.AspNetCore.Http.StatusCodes.Status409Conflict, databaseValue);
        }
        
        // Set new properties
        existingItem.Id = item.Id;
        existingItem.ParentId = item.ParentId;
        existingItem.Name = item.Name;

        // Save changes
        await dbContext.SaveChangesAsync();
        
        // Now return the updated item
        // Now you should map the entity properties back to a new domain model...
        var result = new ItemInfo
        {
            Id = existingItem.Id,
            ParentId = existingItem.ParentId,
            Name = existingItem.Name,
            ConcurrencyStamp = Convert.ToBase64String(existingItem.ConcurrencyStamp),
        };
        return Ok(item);
    }
}

現在,當您嘗試從客戶端更新您的項目並收到 409Conflict 狀態代碼時,您應該決定如何處理此問題。 我選擇在相應的輸入框下方顯示數據庫值。

你可以在這里找到完整的實現

您必須首先從數據庫中獲取實體,然后更新實體。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM