【问题标题】:Dynamically updating certain properties through Entity Framework and JSON (C#)通过实体框架和 JSON (C#) 动态更新某些属性
【发布时间】:2017-01-02 22:26:39
【问题描述】:

我有一个 .NET Core API,它应该使用 Entity Framework Core 更新数据库中的实体。

当用户编辑现有条目时,编辑表单只发回编辑后的数据,而不是完整的实体。

假设我们有一家商店:

public class Shop {
    public int ShopID { get;set;}
    public string Name { get;set;}
    public string Address { get;set;}
}

现在,用户编辑并保存地址。发送回 API 的数据将是 ShopID 和地址。但是,使用下面的模型绑定会将 Name 设置为 NULL,这是合乎逻辑的,因为它实际上并没有被传入。

[Route("~/shop/[action]")]
public IActionResult Update([FromBody] Shop shop)
{
    _context.Shops.Update(shop);
    _context.SaveChanges();
    return new JsonResult(new { result = true });
}

因此,由于我不知道可能会更新哪些属性(实际上,还有更多属性),因此我需要某种方式来动态更新仅通过 POST 请求发送的字段。

提前致谢。

【问题讨论】:

    标签: c# json entity-framework asp.net-core model-binding


    【解决方案1】:

    DbSet<T>不包含Update方法,所以你应该先加载实体,然后改变属性值,然后调用SaveChanges

    [Route("~/shop/[action]")]
    public IActionResult Update([FromBody] Shop shop)
    {
        var shopData = _context.Shops.Single(s => s.Id == shop.ShopId);
    
        if (shop.Name != null)
            shopData.Name = shop.Name;
    
        if (shop.Address != null)
            shopData.Address = shop.Address;
    
        _context.SaveChanges();
        return new JsonResult(new { result = true });
    }
    

    检查和复制每个属性都很烦人,您可以使用 Automapper 之类的库:

    [Route("~/shop/[action]")]
    public IActionResult Update([FromBody] Shop shop)
    {
        var shopData = _context.Shops.Single(s => s.Id == shop.ShopId);
    
        // Copying properties to existing object
        mapper.Map<Shop, Shop>(shop, shopData);
    
        _context.SaveChanges();
        return new JsonResult(new { result = true });
    }
    

    要跳过空属性,请参阅答案Automapper skip null values with custom resolver

    【讨论】:

    • 如此接近,但仍有一段路要走。 AutoMapper 看起来很棒,我看了看,但答案似乎与最新版本过时了,因为.ForAllMembers(opt =&gt; opt.Condition(srs =&gt; !srs.IsSourceValueNull)); 实际上并不包含 IsSourceValueNull。另一个提到实现IValueResolver 似乎也无效,因为该接口现在需要三种类型public interface IValueResolver&lt;in TSource, in TDestination, TDestMember&gt;。还是我完全愚蠢?
    • 如我所见,这里有答案:github.com/AutoMapper/AutoMapper/issues/1406.ForAllMembers(x =&gt; x.Condition(y =&gt; y != null))
    • 谢谢,看起来可以工作Q 作为参考,EF Core 实际上有方法 .Update()。他们的在线文档中似乎没有记录,但绝对有效,并且在 VS intellisense 中。
    • @Max,谢谢。我会试着找到信息,虽然我不能简单地用谷歌搜索方法DbSet&lt;T&gt;.Update
    【解决方案2】:

    我没有测试它,但代码应该如下所示:

    var entry = _context.Shops.Update(shop);
    foreach (var property in entry.Entity.GetType().GetTypeInfo().DeclaredProperties)
    {
          var currentValue = entry.Property(property.Name).CurrentValue;
          if (currentValue == null)
                entry.Property(property.Name).IsModified = false;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多