AutoMapper - отображение выражений из двух источников вызывает исключение - PullRequest
0 голосов
/ 02 мая 2018

Я использую 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());

У меня есть Rest API, который предоставляет UserViewModel и должен позволять фильтровать результаты по 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 игнорировал все части выражения, которые игнорируются.

т.

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 хранятся в двух отдельных базах данных, поэтому они выбираются из БД с использованием двух разных контекстов БД.

Редактировать

Я также пробовал проекцию Automapper, которая, кажется, правильно выбирает данные, но отдельно извлекает все связанные коллекции (В моем вопросе я предоставил упрощенную модель, чтобы лучше объяснить проблему, но реальные сущности зависят от одного до -много отношения). Другая проблема заключается в том, что он также немного нарушает архитектуру, так как мне бы пришлось получить GetQueryable () из репозитория и построить запрос в сервисе вместо прямой передачи всех параметров в репозиторий.

var usersA = _readOnlyRepository.GetQueryable<UserA>().ProjectTo<UserViewModel>().Where(filter).ToList();
var usersB = _readOnlyRepository.GetQueryable<UserB>().ProjectTo<UserViewModel>().Where(filter).ToList();
...