从 JSON 字符串映射到 IEnumerable 字符串时缺少类型映射配置或不受支持的映射

问题描述 投票:0回答:1

我有一个代表用户和分配给该用户的角色的域模型:

public class UserRoles : AggregateRoot<Guid>
{
    public string Email { get; private set; }
    public IEnumerable<string> Roles { get; private set; }

    public UserRoles(Guid id, string email, IEnumerable<string> roles) : base(id)
    {
        Email = email;
        Roles = roles;
    }
}

我将分配给用户的角色存储为 JSON 字符串,在 PostgreSQL 中作为

jsonb
列类型。这是数据库实体:

public class UserRolesEntity
{
    public Guid Id { get; set; }
    public string Email { get; set; } = null!;
    public string Roles { get; set; } = null!;
}

Roles
字符串在数据库中存储为如下所示:

["administrator", "engineer", "manager"]

数据库层使用

EntityFrameworkCore
,带有
PostgreSql
包。

假设我正确设置了所有必要的内容:

DbContext
、表、列等。这是从数据库获取数据并将其转换回域模型的存储库:

public class UserRolesRepository : IUserRolesRepository
{
    private readonly IamDbContext _iamDbContext;
    private readonly IObjectMapper _objectMapper;

    public UserRolesRepository(...)
    {...}

    public async Task<UserRoles?> GetByEmailAsync(string email, CancellationToken...)
    {
        var dbEntity = await _iamDbContext.UserRolesList
            .SingleOrDefaultAsync(x => x.Email == email, cancellationToken);

        if (dbEntity == null)
        {
            return null;
        }

        return _objectMapper.Map<UserRolesEntity, UserRoles>(dbEntity);
    }
}

IObjectMapper
是ABP的映射器接口。我使用
AutoMapper
作为其实现。这是映射配置文件:

public class DbEntityToDomainModelProfile : Profile
{
    public DbEntityToDomainModelProfile()
    {
        CreateMap<UserRolesEntity, UserRoles>()
            .ForMember(dest => dest.Roles, opt => opt.MapFrom<JsonStringToUserRolesResolver>())
            .Ignore(dest => dest.ConcurrencyStamp)
            .Ignore(dest => dest.ExtraProperties)
            .DisableCtorValidation();
    }
}

public class JsonStringToUserRolesResolver : IValueResolver<UserRolesEntity, UserRoles, IEnumerable<string>>
{
    public IEnumerable<string> Resolve(UserRolesEntity source, UserRoles dest, 
        IEnumerable<string> destMember, ResolutionContext context)
    {
        // System.Text.Json
        var userRoles = JsonSerializer.Deserialize<IEnumerable<string>>(source.Roles);
        if (userRoles == null)
        {
            return Enumerable.Empty<string>();
        }

        return userRoles;
    }
}

我有这个值解析器来将我存储在数据库中的 JSON 字符串反序列化为 IEnumerable 字符串,但是当我运行它时,我得到:

AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.

Mapping types:
String -> IEnumerable`1
System.String -> System.Collections.Generic.IEnumerable`1

这是我设置的简化版本:https://dotnetfiddle.net/75ZnMc

使用值解析器,我期望 JSON 字符串能够成功反序列化为 IEnumerable 字符串。


解决方法#1

https://dotnetfiddle.net/eO6jvj

如果我将

roles
构造函数中的
UserRoles
参数重命名为其他名称,并在其中添加无参数构造函数,它将起作用。但我无法解释为什么!

public class UserRoles : AggregateRoot<Guid>
{
    ...

    private UserRoles() { }

    public UserRoles(Guid id, string email, IEnumerable<string> roleList) : base(id)
    {
        Email = email;
        Roles = roleList;
    }
}
c# asp.net-core domain-driven-design automapper abp
1个回答
0
投票

该异常的原因是 AutoMapper 找不到与配置的映射匹配的构造函数参数。

您有两种选择来实现您想要的目标:

  • 使用
    .ForCtorParam("roles", opt => opt.MapFrom(src => JsonSerializer.Deserialize<IEnumerable<string>>(src.Roles, new JsonSerializerOptions())));
    代替
    .ForMember
  • 将默认构造函数添加到目标类型,以便可以创建空对象并填充其值

P。 S. 我创建了 AutoMapper 扩展来简化代码。您可以写

CreateMap<T1, T2>().From(...).To(...)
而不是
ForMember({long expression configuration here})
。这是链接https://www.nuget.org/packages/PetrolMuffin.AutoMapper.Extensions

© www.soinside.com 2019 - 2024. All rights reserved.