将 IQueryables 的“列表”应用到目标?

Inx*_*x51 1 c# entity-framework iqueryable

我有这个想法来创建一个执行不同类型操作的 IQueryables 的“列表”。

所以基本上:

var query1 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Name == "Ronald");
var query2 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Age == 43);
var query3 = Enumerable.Empty<Person>().AsQueryable().Select(e => e.EyeColor);

var listOfQueries = new List<IQueryable<Person>
{
    query1,
    query2,
    query3
};
Run Code Online (Sandbox Code Playgroud)

现在,我也有这个充满“Persons”的 DbSet,我想“应用”针对该 DbSet 的所有查询。我该怎么做呢?有可能吗?

更新的示例:

        var personQueryFactory = new PersonQueryFactory();
        var personQueryByFirstname = personQueryFactory.CreateQueryByFirstname("Ronald");           //Query by Firstname.
        var personQueryByAge = personQueryFactory.CreateQueryByAge(42);                             //Query by age.
        var personQueryByHasChildWithAgeOver = personQueryFactory.CreateQueryByChildAgeOver(25);    //Query using a "join" to the child-relationship.
        var personQuerySkip = personQueryFactory.Take(5);                                           //Only get the 5 first matching the queries.

        var personQuery = personQueryFactory.AggregateQueries                                       //Aggragate all the queries into one single query.
        (
            personQueryByFirstname,
            personQueryByAge,
            personQueryByHasChildWithAgeOver,
            personQuerySkip
        );

        var personSurnames = personsService.Query(personQuery, e => new { Surname = e.Surname });          //Get only the surname of the first 5 persons with a firstname of "Ronald" with the age 42 and that has a child thats over 25 years old.
        var personDomainObjects = personsService.Query<DomainPerson>(personQuery);          //Get the first 5 persons as a domain-object (mapping behind the "scenes") with a firstname of "Ronald" with the age 42 and that has a child thats over 25 years old.
        var personDaos = personsService.Query(personQuery);          //Get the first 5 persons as a DAO-objects/entityframework-entities with a firstname of "Ronald" with the age 42 and that has a child thats over 25 years old.
Run Code Online (Sandbox Code Playgroud)

这样做的原因是创建一种更“统一”的方式来创建和重用预定义查询,然后能够针对 DbSet 执行它们并将结果作为域对象而不是“实体”返回。框架模型/对象”

Fla*_*ter 5

这是可能的,但您需要稍微重新构建您的方法。


储存过滤器

var query1 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Name == "Ronald");
var query2 = Enumerable.Empty<Person>().AsQueryable().Where(e => e.Age == 43);
var query3 = Enumerable.Empty<Person>().AsQueryable().Select(e => e.EyeColor);
Run Code Online (Sandbox Code Playgroud)

阅读您的意图,您实际上并不想要处理IQueryable对象,而是想要处理您提供给方法的参数Where

编辑:我错过了第三个是 a Select(),而不是Where()。我已经调整了答案的其余部分,就好像这也是一个Where(). 请参阅下面的评论,了解我对为什么不能轻松混合的Select()回应Where()

Func<Person,bool> filter1  = (e => e.Name == "Ronald");
Func<Person,bool> filter2  = (e => e.Age == 43);
Func<Person,bool> filter3  = (e => e.EyeColor == "Blue");
Run Code Online (Sandbox Code Playgroud)

这存储相同的信息(过滤条件),但它不会将每个过滤器包装在IQueryable自己的过滤器中。

简短的解释

注意Func<A,B>符号。在本例中,A是输入类型 ( Person),B是输出类型 ( bool)。

这可以进一步扩展。AFunc<string,Person,bool>有两个输入参数 ( string, Person) 和一个输出参数 ( bool)。一个使用示例:

Func<string, Person, bool> filter = (inputString, inputPerson) => inputString == "TEST" && inputPerson.Age > 35;

始终有一个输出参数(最后一种类型)。所有其他提到的类型都是输入参数


将过滤器放入列表中

直观上,sinceFunc<Person,bool>代表单个过滤器;您可以使用 来表示过滤器列表List<Func<Person,bool>>

嵌套泛型类型有点难以阅读,但它确实像任何其他List<T>.

List<Func<Person,bool>> listOfFilters = new List<Func<Person,bool>>()
{
    (e => e.Name == "Ronald"),
    (e => e.Age == 43),
    (e => e.EyeColor == "Blue")
};
Run Code Online (Sandbox Code Playgroud)

执行过滤器

你很幸运。因为您想要应用所有过滤器(逻辑 AND),所以您可以通过堆叠它们来轻松完成此操作:

var myFilteredData = myContext.Set<Person>()
                                 .Where(filter1)
                                 .Where(filter2)
                                 .Where(filter3)
                                 .ToList();
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用的是List<Func<Person,bool>>

var myFilteredData = myContext.Set<Person>().AsQueryable();

foreach(var filter in listOfFilters)
{
    myFilteredData = myFilteredData.Where(filter);
}
Run Code Online (Sandbox Code Playgroud)

边缘案例

然而,如果您试图查找符合一个或多个过滤器(逻辑或)的所有项目,则变得稍微困难​​一些。

完整的答案相当复杂。。您可以在这里查看。

但是,假设您在已知变量中设置了过滤器,则有一个更简单的方法

Func<Person, bool> filterCombined = 
              e => filter1(e) || filter2(e) || filter3(e);

var myFilteredData = myContext.Set<Person>()
                                 .Where(filterCombined)
                                 .ToList();
Run Code Online (Sandbox Code Playgroud)