【问题标题】:Update only the given values (Entity Framework)仅更新给定值(实体框架)
【发布时间】:2020-07-05 16:13:06
【问题描述】:

我试图仅通过动态发送到 API 的值来更新实体,因此每次客户端向我的 api 发送不同的值时,它只会更改给定的值。

这是我的实体

    public class Administrator
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string Role { get; set; }
        public int Phone { get; set; }
    }

这是我的存储库:

public Task<bool> UpdateAdmin(Administrator admin)
        {
            if (admin != null)
            {
                _context.Admins.Update(admin);
                Commit();
                return Task.FromResult(true);
            }
            else
            {
                return Task.FromResult(false);
            }
        }

假设我只想更新电话号码,我只使用新电话号码发送数据,但其余属性也更改为 null。如何只更新给定的?

谢谢

【问题讨论】:

  • 第一:不要将整个实体发送给客户端,尤其是不是部分填充的。使用“知道”哪个属性被修改的视图模型。一旦你有了它,有几种方法可以进行点更新,所有这些都归结为将一个属性标记为已修改。

标签: c# asp.net-core sql-server-2005 entity-framework-core


【解决方案1】:

更新

根据您的评论,admin 收到不同的字段内容 每次。

因此您可以使用reflectiondynamically 确定admin 接受的每个字段的值是否为空。如果不是,则替换data对应字段的值。

public Task<bool> UpdateAdmin(Administrator admin)
        {
            if (admin != null)
            {   
                var data = _context.Admins.Find(admin.Id);
               
                Type t = typeof(Administrator);
                PropertyInfo[] propInfos = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var item in propInfos)
                {
                   var fieldValue = item.GetValue(admin);
                   if (fieldValue != null)
                   {
                      item.SetValue(data, fieldValue);
                   }
                 }

                  _context.Admins.Update(data);
                  Commit();
                  return Task.FromResult(true);
            }
            else
            {
                return Task.FromResult(false);
            }
        }

【讨论】:

  • 这不仅仅是电话字段,而是想象一下对象管理员每次都会向您发送不同的密钥。例如,第一个请求将是电话和姓名,第二个请求将是电子邮件和密码,第三个请求将是唯一的密码。但是每次我希望存储库只更新给定的值而不是整个对象/表。这是可能的还是我必须为每一个创建请求?
  • @Darmon,如果每次传入不同的字段值,那么最好的办法是通过reflection动态获取每个字段的名称,然后判断对应的值是否为null。我已经修改了我的回复,希望对你有帮助。
  • 我会检查并告诉你,谢谢@Yongqing Yu
【解决方案2】:

您需要使用 JsonPatchDocument

这是我做类似事情的示例代码

//get the instance of admin you want to update
var adminInstance = GetAdmin....//get your admin

//partial update -> this how you create a patch doc with C#
var patchDoc = new JsonPatchDocument<Admin>();
patchDoc.Replace(x => x.phone, "put new phone number");//for any other property do x.propertyName
patchDoc.ApplyTo(adminInstance)// apply the patch doc to the instance you want to update
await UpdateAdmin(adminInstance)//your update method look good

//for people trying to do this with an api serialize the patch doc then send it to api
var adminDto =JsonConvert.SerializeObject(patchDoc);



//this is an api example
[HttpPatch("{adminId}")]
public async Task<ActionResult> UpdateAdmin(string adminId, JsonPatchDocument<Admin> patchDocument)
{
  var admin= await _adminRespository.GetAsync(admin);//get the admin you want to update

  patchDocument.ApplyTo(admin); //apply patch doc to the admin

  await _adminRespository.UpdateAsync(admin); //pass admin to your repo

  await _adminRespository.SaveAsync();

  return NoContent();
  }

在存储库中,您不必做任何复杂的事情,只需将模型作为更新传递,所有工作都由 json 补丁文档完成。

要了解有关补丁文档的更多信息

http://jsonpatch.com/

如果您也可以使用本文提供的解决方案来实现相同的目标 Entity Framework validation with partial updates

【讨论】:

  • 如果 OP 没有使用 (auto?)mapper 怎么办?
  • 我提供的代码是一个示例。 OP可以从数据库中获取模型,并将json补丁文档直接应用到他从数据库中获取的模型中。它没有什么区别。 json 补丁文档被应用于 OP 选择的对象。就我而言,我选择 dto 是因为它是最佳实践。 OP不必这样做。@GuruStron
  • 我不太明白这个补丁的用途是什么...我的问题是,是否可以仅通过填充值来更新 Administrator 对象?例如 Password 和 Phone 是空的,但我不希望数据库将它们设为 null 而只是不更改当前值。我希望我能正确解释自己
  • 您可以在将更新发送到 dbcontext 之前执行更新,或者您可以配置 ef 来帮助您完成更新。或者你可以手动完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 2023-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多