json .NET核心API -使用DTO对象更新时更新所有字段

roejwanj  于 2022-12-20  发布在  .NET
关注(0)|答案(3)|浏览(148)

我创建了一个.NET Core API项目,如下所示。一切都很好。但是当我发送一个小JSON文件时,DTO中的空字段会反映在数据库中。那么我如何只更新提交的字段呢?
当我只发送JSON对象中的name字段时,它会更新所有其他字段,我如何在SaveChangesAsync中做到这一点?
当我只发送JSON对象中的name字段时,它会将所有字段记录为null。如何防止这种情况?换句话说,只有发送的数据需要更新,而其他数据则需要记录为原始值。有没有办法在dbcontext对象中实现这一点?
我正在发送一个如下所示的JSON,但是因为JSON对象中的description字段为空,所以在数据库中它被更改为null

{
  "id": 2,
  "name": "test"
}

CompanyController,我通过主体发送JSON对象:

[HttpPut]
public async Task<IActionResult> Update([FromBody] CompanyUpdateDto updateCompany)
{
    await _service.UpdateAsync(_mapper.Map<Company>(updateCompany));
    return CreateActionResult(CustomResponseDto<CompanyUpdateDto>.Success(204));
}

我发送我的updatedDto对象,有时发送namedescription字段,有时只发送name字段。

public class CompanyUpdateDto
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public string? Description { get; set; }
    public DateTime? UpdatedDate { get; set; }
}

CompanyModel

public class Company
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public string? Description { get; set; }
    public DateTime? CreatedDate { get; set; }
    public DateTime? UpdatedDate { get; set; }
}

DataContext

public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
    foreach (var item in ChangeTracker.Entries())
    {
        if (item.Entity is BaseEntity entityReference)
        {
            switch (item.State)
            {
                case EntityState.Added:
                    {
                        entityReference.CreatedDate = DateTime.UtcNow;
                        break;
                    }
                case EntityState.Modified:
                    {
                        Entry(entityReference).Property(x => x.CreatedDate).IsModified = false;
                        break;
                    }
            }
        }
    }
    return base.SaveChangesAsync(cancellationToken);
}
vaj7vani

vaj7vani1#

使用AutoMapper,您可以定义一个规则,该规则仅在源成员不是null通过.Condition()时才从源成员Map到目标成员。
你可以参考这里的例子。

CreateMap<CompanyUpdateDto, Company>()
    .ForAllMembers(opt => opt.Condition((src, dest, value) => value != null));

Demo @ .NET Fiddle
需要注意的是,您需要获取现有实体,并将其与接收到的要更新的对象进行Map,如下所示:

[HttpPut]
public async Task<IActionResult> Update([FromBody] CompanyUpdateDto updateCompany)
{
    // Get existing entity by id (Example)
    var _company = await _service.GetAsync(updateCompany.Id);
    
    // Map source to destination
    _mapper.Map<CompanyUpdateDto, Company>(updateCompany, _company);

    await _service.UpdateAsync(_company);
    return CreateActionResult(CustomResponseDto<CompanyUpdateDto>.Success(204));
}
b1zrtrql

b1zrtrql2#

您也可以在序列化期间忽略空值:

var company = new CompanyUpdateDto();
 company.Description = "New description";
 JsonSerializerOptions options = new()
     {
          DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
      };

  var serialized = JsonSerializer.Serialize(company,options);
zi8p0yeb

zi8p0yeb3#

您必须在此处为API更新操作做出设计决策。
1.获取并完全放置对象。
检索对象时,Get操作必须返回对象的全部详细信息。然后,当任何字段更改时,客户端将把对象全部发送回Put端点。这样,您将保留所有字段的值。
但是,在某些情况下,您只想公开字段的子集,而保留某些字段不变或由系统更新。在这些情况下,您必须通过某些标识符从数据库中检索对象,然后从传入对象中分配字段。
1.使用JSON Patch
您将拥有资源的“修正程式”端点。在要求主体中,您可以指定对象的作业以及已变更的字段。收到要求时,您将根据要求主体中的作业和字段套用变更。
第二种选择的缺点是客户机必须遵循JSON Patch标准。

相关问题