简体   繁体   English

Automapper Expression 将一个属性映射到多个

[英]Automapper Expression mapping one property to many

I'm running a WebAPI,我正在运行一个 WebAPI,

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

My LocaleDto PK is a composite key of 2 FK - LanguageCode and CountryCode我的 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; }
    }

I would like to map LocaleDto to LocaleViewModel, where Id is build based on the following pattern languageCode-CountryCode ie.我想将 map LocaleDto 转换为 LocaleViewModel,其中Id是基于以下模式languageCode-CountryCode 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; }
    }

The following mapping works just fine when I map one object to another using a static helper method:当我使用 static 辅助方法 map 一个 object 到另一个时,以下映射工作得很好:

  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;
        }

But when I map the expression, the result is not understandable in LINQ to SQL, cause it contains the helper LocalisationHelper.ToLocaleCode.但是当我使用 map 表达式时,在 LINQ 到 SQL 中的结果是无法理解的,因为它包含助手 LocalisationHelper.ToLocaleCode。

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

Inspect of entityFilter:检查 entityFilter:

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

Exception例外

     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.

Is there a way to differently map those properties in Automapper so the result can be translated to SQL, without the need of switching to client evaluation?有没有办法在 Automapper 中对这些属性进行不同的 map 以便结果可以转换为 SQL,而无需切换到客户端评估?

What if you tried instead of using a static function evaluate the expression directly如果您尝试而不是使用 static function 直接评估表达式怎么办

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

The Where condition in your current linq is generated on the server , and your server does not define the LocalisationHelper.ToLocaleCode method, so this exception will occur.你当前的 linq 中的Where条件是on the server生成的,而你的服务器没有定义 LocalisationHelper.ToLocaleCode 方法,所以会出现这个异常。

To solve this problem, you only need to convert the DbSet<LocaleDto> to list or enumerable before the where condition(which has mentioned in the exception), so that the where condition can be guaranteed to run under the client condition .要解决这个问题,只需要在where条件之前convert the DbSet<LocaleDto> to list or enumerable (异常中已经提到),这样可以保证where条件the client condition运行。

Change your code as follow:更改您的代码如下:

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

Update更新

Here is the second method:这是第二种方法:

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();

You can also refer to this .你也可以参考这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM