使用EF6进行Automapper Projection和LINQ查询

时间:2015-02-04 11:47:46

标签: linq entity-framework-6 automapper

我们有一个支持多种语言的遗留系统。特定于语言的字段在每个数据库行上都是重复的 - 每种语言都使用语言代码作为列名前缀。在我们的EF6模型中,我们使用LocalizedString复杂类型来保存每个字符串属性的所有翻译值。基于这篇文章:http://patrickdesjardins.com/blog/how-to-have-localized-string-with-mvc-and-entity-framework

我能够根据Web应用程序线程CurrentCulture定义映射,并使用EF6在linq投影中使用它。但我对视图模型中的映射代码的方式并不完全满意。

示例域类,ViewModel和映射:


public partial class CountryDomain
{
    public CountryDomain()
    {
        CountryName = new LocalizedString();
    }

    public long CountryId { get; set; }
    public LocalizedString CountryName { get; set; }
    public string CountryCode { get; set; }
}

public class CountryViewModel
{
    public long CountryId { get; set; }
    public string CountryName { get; set; }
    public string CountryCode { get; set; }
}

public void CreateMap() 
{ 
Mapper.CreateMap<CountryDomain, CountryViewModel>()
  .ForMember(dest => dest.CountryName, opt => opt.MapFrom(src =>
     Context.TwoLetterISOLanguageName == "en" ? src.CountryName.ValueEn :
     Context.TwoLetterISOLanguageName == "da" ? src.CountryName.ValueDa :
     src.CountryName.ValueNo));

}


我想将MapFrom的内容移动到一般位置,并仍保留对LINQ Projection Queries的支持。假设我们突然不得不添加对新语言的支持,然后必须更新以更新许多视图模型。

内联网络运算符(?)被转换为SQL:CASE WHEN .... END语句,只从数据库加载正确的字段,这是非常好的。

你们有没有解决这个仍然支持LINQ查询投影的问题?

2 个答案:

答案 0 :(得分:1)

您可以使用ProjectUsing:

string lang = null;
Mapper.CreateMap<LocalizedString, string>().ProjectUsing(src =>
 lang == "en" ? src.ValueEn :
 lang == "da" ? src.ValueDa :
 src.ValueNo);

在制图期间:

context.Countries.Project().To<CountryViewModel>(new { lang = Context.TwoLetterISOLanguageName });

我切换到参数化投影,因为我不确定每个请求是否更改了“Context”值。如果它在应用程序的生命周期内被读取一次,您可以采用硬编码的方式,如果它发生了变化,那么我的方式可以确保它通过查询进行参数化。

答案 1 :(得分:0)

这是更好的解决方案!谢谢!

为了支持来自内存中对象的映射,我假设需要额外的:


map.ConvertUsing(src =>    
    Context.TwoLetterISOLanguageName == "en" ? src.ValueEn :
    Context.TwoLetterISOLanguageName == "da" ? src.ValueDa :
    src.ValueNo);    

var vm = Mapper.Map<List<CountryViewModel>>(list);