Automapper Expression отображает одно свойство на множество - PullRequest
1 голос
/ 23 апреля 2020

Я использую WebAPI,

Asp.Net Core 3.1
Automapper: 9.0
Automapper.Extensions.ExpressionMapping: 3.1

Мой LocaleDto PK представляет собой составной ключ из 2 FK - LanguageCode и CountryCode

  public class LocaleDto 
    {
        [Key, ForeignKey(nameof(Language)), Column(Order = 0)]
        public string LanguageCode { get; set; }

        public LanguageDto Language { get; set; }

        [Key, ForeignKey(nameof(Country)), Column(Order = 1)]
        public string CountryCode { get; set; }

        public CountryDto Country { get; set; }
    }

Я хотел бы сопоставить LocaleDto с LocaleViewModel, где Id - это сборка, основанная на следующем шаблоне languageCode-CountryCode ie. en-GB

 public class LocaleViewModel 
    {
        public string Id {get;set;}
        public string LanguageCode { get; set; }
        public LanguageViewModel Language { get; set; }
        public string CountryCode { get; set; }
        public CountryViewModel Country { get; set; }
    }

Следующее отображение отлично работает, когда я сопоставляю один объект другому, используя вспомогательный метод stati c:

  CreateMap<LocaleDto, LocaleViewModel>()
                    .ForMember(dest => dest.Id, opt => opt.MapFrom(src => LocalisationHelper.ToLocaleCode(src.LanguageCode, src.CountryCode)));

            CreateMap<LocaleViewModel, LocaleDto>()
                    .ForMember(dest => dest.LanguageCode, src => src.MapFrom(x => x.LanguageCode))
                    .ForMember(dest => dest.CountryCode, src => src.MapFrom(x => x.CountryCode));
...
  public static string ToLocaleCode(string languageCode, string countryCode)
        {
            if (!string.IsNullOrEmpty(languageCode) && !string.IsNullOrEmpty(countryCode))
            {
                return $"{languageCode}-{countryCode}";
            }
            return null;
        }

Но когда я сопоставляю выражение, результат не понятен в LINQ для SQL, поскольку он содержит вспомогательный LocalisationHelper.ToLocaleCode.

Expression<Func<LocaleViewModel, bool>> filter = x => x.Id == "en-GB";
var entityFilter = mapper.MapExpression<Expression<Func<LocaleDto, bool>>>(filter);

Проверка entityFilter:

 {Param_0 => (ToLocaleCode(Param_0.LanguageCode, Param_0.CountryCode) == "en-GB")}

Исключение

     The LINQ expression 'DbSet<LocaleDto>
         .Where(l => LocalisationHelper.ToLocaleCode(
             languageCode: l.LanguageCode, 
             countryCode: l.CountryCode) == "en-GB")' could not be translated. Either rewrite the query in a form that can be translated,
     or switch to client evaluation explicitly by inserting a call to
     either AsEnumerable(), AsAsyncEnumerable(), ToList(), or
     ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for
     more information.

Есть ли способ по-разному сопоставить эти свойства в Automapper, чтобы результат можно было преобразовать в SQL без необходимости переключения на оценку клиента?

Ответы [ 2 ]

1 голос
/ 25 апреля 2020

Что если вы попытаетесь вместо использования функции c вычислить выражение непосредственно

CreateMap<LocaleDto, LocaleViewModel>()
   .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.LanguageCode + "-" + src.CountryCode));
0 голосов
/ 25 апреля 2020

Создается условие Where в вашем текущем linq on the server, и ваш сервер не определяет метод LocalisationHelper.ToLocaleCode, поэтому возникнет это исключение.

Чтобы решить эту проблему, вам нужно только до convert the DbSet<LocaleDto> to list or enumerable перед условием where (которое упоминалось в исключении), так что условие where может быть гарантированно выполнено в the client condition.

Измените код следующим образом:

DbSet<LocaleDto>.ToList().Where(l => LocalisationHelper.ToLocaleCode(l.LanguageCode,l.CountryCode) == "en-GB")

Обновление

Вот второй метод:

Func<LocaleDto, bool> IsMatch = (x) =>
            ((!string.IsNullOrEmpty(x.LanguageCode) && !string.IsNullOrEmpty(x.CountryCode))
            ? $"{x.LanguageCode}-{x.CountryCode}" : null) == "en-GB";

var query = DbSet<LocaleDto>.Where(IsMatch).ToList();

Вы также можете обратиться к this .

...