繁体   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