问题
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