[英]Dynamically passing properties in Select for projection in Entity Framework
有沒有一種方法可以動態傳遞要從Select中從數據庫檢索的屬性,我不知道我事先需要的屬性,也不想在存儲庫中編寫條件。
我不想一次檢索所有字段,只是根據某些條件需要檢索的字段。
例如:
public class Student
{
public string Property1 {get; set;}
public string Property2 {get; set;}
//other properties here
[NotMapped]
public string Selected
{
if(condition)
return Property1;
else
return Property2;
}
}
在服務層中
query.Select(s => new StudentViewModel
{
Value = s.Selected; //this one will get the property we want based on a condition
//other stuff here
//OtherValue = s.OtherProperty
}
).FirstOrDefault();
選擇
一種簡單但難看的方法是使用選擇器:
query.Select(Selector()).FirstOrDefault();
選擇器可能如下所示:
private static Expression<Func<Student, StudentViewModel>> Selector()
{
if (Condition())
return x => new StudentViewModel
{
Name = x.Property1,
OtherName = x.OtherName
};
return x => new StudentViewModel
{
Name = x.Property2,
OtherName = x.OtherName
};
}
如您所見,這里明顯的缺點是您需要復制/粘貼所有其他選定的屬性。 這就是為什么它很丑。
AutoMapper
CONFIGS
您可以將AutoMapper用於不同的配置。 首先,您需要為所有不需要動態的屬性定義一個標准映射。
public static void AddStandardStudentMap(this IMappingExpression<Student, StudentViewModel> map) { map.ForMember(dest => dest.OtherName, opt => opt.MapFrom(src => src.OtherProperty)) .ForMember(dest => dest.OtherName2, opt => opt.MapFrom(src => src.OtherProperty2)); // you can concat .ForMember() for each property you need. }
接下來,您需要定義不同的配置,並將AddStandardStudentMap
方法添加到每個靜態映射。
var config1 = new MapperConfiguration(cfg => cfg.CreateMap<Student, StudentViewModel>() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Property1)) .AddStandardStudentMap() ); var config2 = new MapperConfiguration(cfg => cfg.CreateMap<Student, StudentViewModel>() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Property2)) .AddStandardStudentMap() );
之后,只需根據您的條件來確定您需要哪個配置
IConfigurationProvider provider; if(Condition()) provider = config1; else provider = config2;
然后代替.Select()
使用:
query.ProjectTo<StudentViewModel>(provider).FirstOrDefault();
如我們所見,此解決方案仍然很丑陋,並且有很多開銷,但是在某些情況下需要它,這就是為什么我在這里說明了這一點。
表達
這有點類似於Configs,但是為您帶來了更大的靈活性和更少的編寫工作。
首先創建一個配置,但是這次使用選擇器
var config = new MapperConfiguration(cfg => cfg.CreateMap<Student, StudentViewModel>() .ForMember(dest => dest.OtherName, opt => opt.MapFrom(src => src.OtherName)) .ForMember(dest => dest.OtherName2, opt => opt.MapFrom(src => src.OtherName2)) // and so on. Map all your properties that are not dynamically. // and then the Selector .ForMember(dest => dest.Name, opt => opt.MapFrom(src => Selector())) );
Selector方法如下所示:
private static Expression<Func<Student, StudentViewModel>> Selector() { if(Condition()) return src => src.Property1; else return src => src.Property2; }
然后像配置解決方案一樣使用它,而不選擇特定的配置:
query.ProjectTo<StudentViewModel>(config).FirstOrDefault();
結論
我知道這是很多輸入,無論有沒有AutoMapper,都有更多的可能性來實現所需的行為。 但是我建議您(基於您提供給我們的信息)將AutoMapper與Expressions一起使用。 它應該提供您所需的靈活性,並且可以擴展為進一步的要求。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.