【问题标题】:How to partial update entity如何部分更新实体
【发布时间】:2021-09-05 18:38:36
【问题描述】:

有人可以展示一个部分更新实体的示例吗? git/docs/stack 中的所有示例都只有 update 方法,它会替换所有字段,即使我发送 null。

看来我需要使用 HttpPatch 和 json-patch。但它有很多额外的代码......

用户实体

 public class User: AbpUser<User>
    {
        [Required(AllowEmptyStrings = true)]
        [StringLength(MaxNameLength)]
        public override string Name { get; set; }

        [Required(AllowEmptyStrings = true)]
        [StringLength(MaxNameLength)]
        public override string Surname { get; set; }

        public string FatherName { get; set; }

        public DateTime BirthDate { get; set; }

        public long? DepartmentId { get; set; }

        public long? ManagerId { get; set; }

        public long? PositionId { get; set; }

        public override string FullName => $"{Surname} {Name} {FatherName}";
    }

CreateUserDto

{
  "name": "Test",
  "surname": "Test",
  "emailAddress": "test@test.test"
}

UpdateUserDto

{
  "id": 1,
  "name": "Василий",
  "surname": "Пупкин",
  "fatherName": "Иванович",
  "birthDate": "1993-02-21",
  "emailAddress": "vasiliyp@test.test",
  "phonenumber": "+79378889911",
  "departmentId": 1,
  "positionId" : 1
}

第二次UpdateUserDto

{
  "id": 1,
  "name": "Василий",
  "surname": "Пупкин",
  "fatherName": "Иванович"
}

第二次更新后,我想获得部分更新,但它会更新所有字段,包括我未发送的字段。例如,PositionId 将为 null,而不是 1。

用户应用服务

        public override async Task<UserDto> UpdateAsync(UpdateUserDto input)
        {
            var user = await _userManager.GetUserByIdAsync(input.Id);

            MapToEntity(input, user);

            return await GetAsync(input);
        }
        protected override async void MapToEntity(UpdateUserDto input, User user)
        {
            ObjectMapper.Map(input, user);
            user.SetNormalizedNames();

            if (!user.DepartmentId.HasValue || user.DepartmentId == 0) return;

            var department = await _departmentRepository.GetAsync((long)user.DepartmentId);
            user.ManagerId = department.ManagerId;
        }

更新

昨天我找到了一种方法:它需要自定义自动映射器来合并模型。

Configuration.Modules.AbpAutoMapper().Configurators.Add(
  cfg => cfg.ForAllMaps((obj, cnfg) => cnfg.ForAllMembers( 
  opts => opts.Condition((src, dest, srcMember) => srcMember != null))));

但是有问题:

  1. DTO 中的所有值类型都必须可以为空,因为自动映射器将获取默认值。
  2. 尽管我已将 DateTime 定义为可为空,但自动转换会将其转换为默认值 (DateTime)。我还没有找到不用拐杖解决这个问题的方法。
if(input.BirthDate == null) input.BirthDate = user.BirthDate;

更新 2

    [AutoMapTo(typeof(User))]
    public class UpdateUserDto : EntityDto<long>
    {
        [StringLength(AbpUserBase.MaxNameLength)]
        public string Name { get; set; }

        [StringLength(AbpUserBase.MaxSurnameLength)]
        public string Surname { get; set; }

        public string FatherName { get; set; }

        public DateTime? BirthDate { get; set; }

        [EmailAddress]
        [StringLength(AbpUserBase.MaxEmailAddressLength)]
        public string EmailAddress { get; set; }

        public string PhoneNumber { get; set; }

        public long? DepartmentId { get; set; }

        public long? PositionId { get; set; }
    }

【问题讨论】:

    标签: aspnetboilerplate


    【解决方案1】:

    您可以使用特定字段创建新的 Dto 并为此创建新的更新函数。

    【讨论】:

    • 他已经定义了新的 DTO,只要新的 Update 方法使用基本的 Update,其余的属性将被 null 或默认值覆盖。
    • 是的,我定义了。昨天我找到了一种方法:它需要自定义自动映射器来合并模型。但我有一些问题:Configuration.Modules.AbpAutoMapper().Configurators.Add( cfg =&gt; cfg.ForAllMaps( (obj, cnfg) =&gt; cnfg.ForAllMembers( opts =&gt; opts.Condition( (src, dest, srcMember) =&gt; srcMember != null) ) ) );
    • 无需自定义您的映射器,您必须从 D 中删除所有属性/字段到您不会应用的 t 中。另一个词用你想要的特定字段创建一个 Dto。
    • 构建 Web API 是最佳实践吗?我认为 Web API 与客户端需要什么接口无关。如果客户端想要将用户实体更新到多个地方 - Web API 应该为所有这些地方提供 1 个更新方法。例如,我的 UI 中有 3 个地方可以编辑用户实体——用户卡、部门列表、文档操作。您是否建议使用自己的 DTO 模型为每个地方创建一个更新?
    • 所以你为所有这三种状态编写了一个端点,如果某些主体以某种方式访问​​该端点,会发生什么?她/他可以改变任何事情。有时我们必须将它们分开。当然这是我的看法,你可以搜索更多。
    猜你喜欢
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    • 2021-04-14
    相关资源
    最近更新 更多