You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Automapper优雅实现用户更新时Attributes的增量更新?

问题描述

我正在实现用户更新接口,更新时会先获取原始UserEntity实体:

public class UserEntity
{
    public Guid Id { get; set; }
    public Dictionary<string, IEnumerable<string>> Attributes { get; set; }
}
var user = await _userService.GetByIdAsync(request.Id);

更新请求定义如下:

public class UpdateUserRequest
{
    public string? MiddleName { get; set; }
    public string? Phone { get; set; }
}

其中MiddleName和Phone需要存入UserEntity的Attributes字典中。我当前使用Automapper映射时,通过UseDestinationValue()保留原有Attributes避免被清空:

_mapper.Map(request, user);

CreateMap<UpdateUserRequest, UserEntity>().ForMember(dst => dst.Attributes, opt => opt.UseDestinationValue());

但目前我通过自定义SetAttributes方法来实现新增或更新Attributes中的字段,写法较为繁琐,想请教是否可以通过Automapper优雅处理该需求?

我的现有实现:

void SetAttributes()
{
    if(!string.IsNullOrEmpty(request.MiddleName))
    {
        if(!user.Attributes.TryGetValue(Constants.Attributes.MiddleName, out var middleName))
        {
            user.Attributes.Add(Constants.Attributes.MiddleName, new string[]
            {
                request.MiddleName
            });
        }
        else
        {
            user.Attributes[Constants.Attributes.MiddleName] = new string[]
            {
                request.MiddleName
            };
        }
    }

    if(!string.IsNullOrEmpty(request.Phone))
    {
        if(!user.Attributes.TryGetValue(Constants.Attributes.PhoneNumber, out var firstName))
        {
            user.Attributes.Add(Constants.Attributes.PhoneNumber, new string[]
            {
                request.Phone
            });
        }
        else
        {
            user.Attributes[Constants.Attributes.PhoneNumber] = new string[]
            {
                request.Phone
            };
        }
    }
}
解决方案

可以通过Automapper的字段映射配置结合自定义逻辑,替代繁琐的SetAttributes方法,以下是两种优雅实现方式:

方式1:逐个字段配置映射逻辑

直接在CreateMap中为每个请求字段添加自定义映射规则,判断字段非空后更新字典:

CreateMap<UpdateUserRequest, UserEntity>()
    // 保留原有Attributes字典实例
    .ForMember(dst => dst.Attributes, opt => opt.UseDestinationValue())
    // 处理MiddleName字段
    .ForMember(dst => dst.Attributes, opt => opt.MapFrom((src, dst) =>
    {
        if (!string.IsNullOrEmpty(src.MiddleName))
        {
            dst.Attributes[Constants.Attributes.MiddleName] = new[] { src.MiddleName };
        }
        return dst.Attributes;
    }))
    // 处理Phone字段
    .ForMember(dst => dst.Attributes, opt => opt.MapFrom((src, dst) =>
    {
        if (!string.IsNullOrEmpty(src.Phone))
        {
            dst.Attributes[Constants.Attributes.PhoneNumber] = new[] { src.Phone };
        }
        return dst.Attributes;
    }));

调用_mapper.Map(request, user)时,会自动完成对应字典项的新增或更新,无需额外调用自定义方法。

方式2:自定义值解析器(复用逻辑)

如果后续需要处理更多字段,可封装通用值解析器减少重复代码:

首先定义通用解析器:

public class UpdateAttributesResolver<TSource> : IValueResolver<TSource, UserEntity, Dictionary<string, IEnumerable<string>>>
{
    private readonly Func<TSource, (string Key, string? Value)> _propertySelector;

    public UpdateAttributesResolver(Func<TSource, (string Key, string? Value)> propertySelector)
    {
        _propertySelector = propertySelector;
    }

    public Dictionary<string, IEnumerable<string>> Resolve(TSource source, UserEntity destination, Dictionary<string, IEnumerable<string>> destMember, ResolutionContext context)
    {
        var (key, value) = _propertySelector(source);
        if (!string.IsNullOrEmpty(value))
        {
            destination.Attributes[key] = new[] { value };
        }
        return destination.Attributes;
    }
}

然后在映射配置中使用:

CreateMap<UpdateUserRequest, UserEntity>()
    .ForMember(dst => dst.Attributes, opt => opt.UseDestinationValue())
    .ForMember(dst => dst.Attributes, opt => opt.AddResolver(new UpdateAttributesResolver<UpdateUserRequest>(src => 
        (Constants.Attributes.MiddleName, src.MiddleName))))
    .ForMember(dst => dst.Attributes, opt => opt.AddResolver(new UpdateAttributesResolver<UpdateUserRequest>(src => 
        (Constants.Attributes.PhoneNumber, src.Phone))));

新增字段时只需添加一行AddResolver即可,扩展性更强。

注意事项

  • 确保UserEntity的Attributes字典在映射前已初始化(比如从数据库获取时不为null),避免空引用异常。
  • 若需要处理字段为null时删除字典项的场景,可在解析器中补充逻辑:当value为null且字典存在对应key时,执行destination.Attributes.Remove(key)。

内容的提问来源于stack exchange,提问作者hoozr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 22:25:48