我使用的是Asp.Net Core 2.0,Automapper 6.2.2
在我的项目中,我希望AutoMapper允许从两个源映射到一个目标(相反)。请考虑以下型号:
class UserA {
public CustomerId {get;set;}
public CustomerName {get;set;}
}
class UserB {
public CustomerId {get;set;}
public CustomerEmail {get;set;}
}
class UserViewModel{
public Id {get;set;}
public CustomerName {get;set;}
public CustomerEmail {get;set;}
}
我的AutoMapper配置文件配置如下:
CreateMap<UserA , UserViewModel>()
.ForMember(dest => dest.Id , opt => opt.MapFrom(src => src.CustomerID))
.ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.CustomerName)).ReverseMap()
.ForAllOtherMembers(x => x.Ignore());
CreateMap<UserB , UserViewModel>()
.ForMember(dest => dest.Id , opt => opt.MapFrom(src => src.CustomerID))
.ForMember(dest => dest.CustomerEmail , opt => opt.MapFrom(src => src.CustomerEmail )).ReverseMap()
.ForAllOtherMembers(x => x.Ignore());
我有一个公开UserViewModel的Rest API,应该允许根据Id,CustomerName或CustomerEmail过滤结果。 API使用者不应该知道CustomerName和CustomerEmail属于哪个实体。
我已经创建了一种服务方法:
public override async Task<IEnumerable<UserViewModel>> GetAsync(Expression<Func<UserViewModel, bool>> filter = null, Expression<Func<IQueryable<UserViewModel>, IOrderedQueryable<UserViewModel>>> orderBy = null, string includeProperties = null, int? skip = null, int? take = null)
现在我想映射两个参数
Expression<Func<UserViewModel, bool>> filter
Expression<Func<IQueryable<UserViewModel>, IOrderedQueryable<UserViewModel>>> orderBy
要
Expression<Func<UserA, bool>> filterA
Expression<Func<IQueryable<UserA>, IOrderedQueryable<UserA>>> orderByA
Expression<Func<UserB, bool>> filterB
Expression<Func<IQueryable<UserB>, IOrderedQueryable<UserB>>> orderByB
但是当我使用UserEmail应用过滤器并希望映射到UserA时,映射会给我一个例外。我希望AutoMapper忽略配置Ignored的表达式的所有部分。
即
var filterA= Mapper.Map<Expression<Func<UserA, bool>>>(filter);
给出例外
ArgumentNullException: Value cannot be null.
Parameter name: memberInfo
AutoMapper.Internal.ReflectionHelper.GetMemberType(MemberInfo memberInfo)
AutoMapperMappingException: Error mapping types.
Mapping types:
Expression1`1 -> Expression`1
System.Linq.Expressions.Expression1`1[[System.Func`2[[Cluster.Users.ViewModel.UserDetailViewModel, Cluster.User, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] -> System.Linq.Expressions.Expression`1[[System.Func`2[[Cluster.Model.SimsModel.UserDetail, Cluster.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
lambda_method(Closure , Expression1<Func<UserDetailViewModel, bool>> , Expression<Func<UserDetail, bool>> , ResolutionContext )
最后一个问题是UserA和UserB存储在两个独立的数据库中,因此它们是使用两个不同的db上下文从数据库中提取的。
修改
我还尝试过Automapper投影,它似乎正确地获取数据,但它分别获取所有相关集合(在我的问题中,我提供了一个简化的模型来更好地解释问题,但真正的实体有依赖的一对多关系)。 另一个问题是它也破坏了体系结构,因为我必须从存储库中获取GetQueryable()并在服务中构建查询,而不是直接将所有参数传递给存储库。
var usersA = _readOnlyRepository.GetQueryable<UserA>().ProjectTo<UserViewModel>().Where(filter).ToList();
var usersB = _readOnlyRepository.GetQueryable<UserB>().ProjectTo<UserViewModel>().Where(filter).ToList();