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 执行它们并将结果作为域对象而不是“实体”返回。框架模型/对象”
这是可能的,但您需要稍微重新构建您的方法。
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)。这可以进一步扩展。A
Func<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)