我有一个代表用户和分配给该用户的角色的域模型:
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 字符串。
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;
}
}
该异常的原因是 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