我正在尝试使用EF,我会根据多对多的关系进行大量过滤。例如,我有人,地点和人员位置表来链接这两者。我也有角色和人员表。
EDIT: Tables:
Person (personid, name)
Personlocation (personid, locationid)
Location (locationid, description)
Personrole (personid, roleid)
Role (roleid, description)
EF将给我个人,角色和位置实体。编辑:由于EF NOT 生成personlocation和personrole实体类型,因此无法在查询中使用它们。
如何创建查询以向我提供具有给定角色的给定位置的所有人员?
在SQL中,查询将是
select p.*
from persons as p
join personlocations as pl on p.personid=pl.personid
join locations as l on pl.locationid=l.locationid
join personroles as pr on p.personid=pr.personid
join roles as r on pr.roleid=r.roleid
where r.description='Student' and l.description='Amsterdam'
我看了,但我似乎无法找到简单的解决方案。
答案 0 :(得分:29)
注意:强>
由于它是在EF v1中,我们 NOT 将 PersonLocation 和 PersonRole 生成为LINQ2SQL所做的实体(上面的答案是LINQ2SQL)场景,不适用于该问题。)
解决方案1:
Persons.Include("Role").Include("Location") // Include to load Role and Location
.Where(p => p.Role.Any(r => r.description == "Student")
&& p.Location.Any(l => l.description == "Amsterdam")).ToList();
这看起来很简单直接,但这会产生丑陋的SQL脚本 而且它的表现还可以。
解决方案2:
这是故障。
// Find out all persons in the role
// Return IQuerable<Person>
var students = Roles.Where(r => r.description == "Student")
.SelectMany(r => r.Person);
// Find out all persons in the location
// Return IQuerable<Person>
var personsInAmsterdam = Locations.Where(l=> l.description == "Amsterdam")
.SelectMany(l=>l.Person);
// Find out the intersection that gives us students in Admsterdam.
// Return List<Person>
var AdmsterdamStudents = students.Intersect(personsInAmsterdam).ToList();
将上述三个步骤合并为一个:
//Return List<Person>
var AdmsterdamStudents = Roles.Where(r => r.description == "Student")
.SelectMany(r => r.Person)
.Intersect
(
Locations
.Where(l=> l.description == "Amsterdam")
.SelectMany(l=>l.Person)
).ToList();
这有点冗长。但是这会生成干净的SQL查询并且运行良好。
答案 1 :(得分:11)
在Lambda:
var persons = Persons.Where(p=>(p.PersonLocations.Select(ps=>ps.Location)
.Where(l=>l.Description == "Amsterdam").Count() > 0)
&& (p.PersonRoles.Select(pr=>pr.Role)
.Where(r=>r.Description == "Student").Count() > 0));
查询结果:
SELECT [t0].[personId] AS [PersonId], [t0].[description] AS [Description]
FROM [Persons] AS [t0]
WHERE (((
SELECT COUNT(*)
FROM [personlocations] AS [t1]
INNER JOIN [Locations] AS [t2] ON [t2].[locationid] = [t1].[locationid]
WHERE ([t2].[description] = @p0) AND ([t1].[personid] = [t0].[personId])
)) > @p1) AND (((
SELECT COUNT(*)
FROM [PersonRoles] AS [t3]
INNER JOIN [Roles] AS [t4] ON [t4].[roleid] = [t3].[roleid]
WHERE ([t4].[description] = @p2) AND ([t3].[personid] = [t0].[personId])
)) > @p3)
使用Contains():
var persons = Persons
.Where(p=>(p.Personlocations.Select(ps=>ps.Location)
.Select(l=>l.Description).Contains("Amsterdam")) &&
(p.PersonRoles.Select(pr=>pr.Role)
.Select(r=>r.Description).Contains("Student")));
查询结果:
SELECT [t0].[personId] AS [PersonId], [t0].[description] AS [Description]
FROM [Persons] AS [t0]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM [personlocations] AS [t1]
INNER JOIN [Locations] AS [t2] ON [t2].[locationid] = [t1].[locationid]
WHERE ([t2].[description] = @p0) AND ([t1].[personid] = [t0].[personId])
)) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [PersonRoles] AS [t3]
INNER JOIN [Roles] AS [t4] ON [t4].[roleid] = [t3].[roleid]
WHERE ([t4].[description] = @p1) AND ([t3].[personid] = [t0].[personId])
))
使用join():
var persons = Persons
.Join(Personlocations, p=>p.PersonId, ps=>ps.Personid,
(p,ps) => new {p,ps})
.Where(a => a.ps.Location.Description =="Amsterdam")
.Join(PersonRoles,
pr=> pr.p.PersonId, r=>r.Personid,(pr,r) => new {pr.p,r})
.Where(a=>a.r.Role.Description=="Student")
.Select(p=> new {p.p});
查询结果:
SELECT [t0].[personId] AS [PersonId], [t0].[description] AS [Description]
FROM [Persons] AS [t0]
INNER JOIN [personlocations] AS [t1] ON [t0].[personId] = [t1].[personid]
INNER JOIN [Locations] AS [t2] ON [t2].[locationid] = [t1].[locationid]
INNER JOIN [PersonRoles] AS [t3] ON [t0].[personId] = [t3].[personid]
INNER JOIN [Roles] AS [t4] ON [t4].[roleid] = [t3].[roleid]
WHERE ([t4].[description] = @p0) AND ([t2].[description] = @p1)
您可能希望测试大数据的速度更快。
祝你好运。Giuliano Lemes
答案 2 :(得分:1)
发现更多信息,实体处理多对多的方式和原因:
答案 3 :(得分:0)
好的,就我所知,LINQ没有任何规定。 Lambda表达式适用于任何()。