问题
I'm running a 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
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. 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:
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.
Expression<Func<LocaleViewModel, bool>> filter = x => x.Id == "en-GB";
var entityFilter = mapper.MapExpression<Expression<Func<LocaleDto, bool>>>(filter);
Inspect of 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?
回答1:
What if you tried instead of using a static function evaluate the expression directly
CreateMap<LocaleDto, LocaleViewModel>()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.LanguageCode + "-" + src.CountryCode));
回答2:
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.
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
.
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 .
来源:https://stackoverflow.com/questions/61392778/automapper-expression-mapping-one-property-to-many