簡體   English   中英

在實體框架中的“選擇投影”中動態傳遞屬性

[英]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

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

    如我們所見,此解決方案仍然很丑陋,並且有很多開銷,但是在某些情況下需要它,這就是為什么我在這里說明了這一點。

  2. 表達

    這有點類似於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM