【问题标题】:Automapper Expression mapping one property to manyAutomapper 表达式将一个属性映射到多个
【发布时间】:2020-04-27 10:19:03
【问题描述】:

我正在运行一个 WebAPI,

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

我的 LocaleDto PK 是 2 个 FK - LanguageCodeCountryCode 的复合键

  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 构建的,即。 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; }
    }

当我使用静态辅助方法将一个对象映射到另一个对象时,以下映射工作得很好:

  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 to 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,而无需切换到客户端评估?

【问题讨论】:

  • 先尝试在 LINQ 中编写,不要使用 AM。然后你就可以把 AM 带回来了。另外搜索以前的解决方案,以前有人这样做过。
  • 直接使用 linq to Dto 就可以了
  • 真的吗? :) 那怎么称呼ToLocaleCode?显然这是另一个代码。
  • 我对您提供的 cmets 感到很困惑。你读过这个问题并完全理解了吗? ToLocaleCode 是映射的助手。它会导致实际问题。如果映射是我要修复的唯一一件事,那么尝试“不首先使用自动映射器”的任何事情的价值是什么..

标签: c# asp.net asp.net-core automapper


【解决方案1】:

如果您尝试直接计算表达式而不是使用静态函数会怎样

CreateMap<LocaleDto, LocaleViewModel>()
   .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.LanguageCode + "-" + src.CountryCode));

【讨论】:

  • 我必须检查添加字符串是否有任何区别,但我在没有帮助器的情况下(直接在映射中)测试了字符串插值 $"{lolaleCode}-{countryCode}" 并且它不起作用。
【解决方案2】:

你当前linq中的Where条件是生成on the server,而你的服务器没有定义LocalisationHelper.ToLocaleCode方法,所以会出现这个异常。

要解决这个问题,只需要在where条件前加上convert the DbSet&lt;LocaleDto&gt; to list or enumerable(在异常中已经提到),这样可以保证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

【讨论】:

  • 这行得通,但那是客户评估,所以我想避免这样做。对于有 10 行左右的语言环境来说,这不是问题,但我在翻译 dto(数百或数千个条目)时遇到了同样的问题。从数据库中获取它们并在内存中过滤掉是不可接受的解决方案
  • @Konrad,我已经更新了我的帖子,你可以尝试另一种方法。
猜你喜欢
  • 2015-01-11
  • 1970-01-01
  • 2020-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 1970-01-01
  • 2011-06-26
相关资源
最近更新 更多