我正在尝试使用EF,我根据多对多关系进行了大量过滤.例如,我有人,地点和人员位置表来链接这两者.我也有角色和人员表.
EDIT: Tables: Person (personid, name) Personlocation (personid, locationid) Location (locationid, description) Personrole (personid, roleid) Role (roleid, description)
EF将为我提供人员,角色和位置实体.编辑:由于EF 不会生成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'
我看了,但我似乎无法找到一个简单的解决方案.
注意:
因为它是在EF V1,我们将不具有PersonLocation和PersonRole像LINQ2SQL做什么实体产生(答案以上domonstrating 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 IQuerablevar students = Roles.Where(r => r.description == "Student") .SelectMany(r => r.Person); // Find out all persons in the location // Return IQuerable var personsInAmsterdam = Locations.Where(l=> l.description == "Amsterdam") .SelectMany(l=>l.Person); // Find out the intersection that gives us students in Admsterdam. // Return List var AdmsterdamStudents = students.Intersect(personsInAmsterdam).ToList();
将上述三个步骤合并为一个:
//Return Listvar AdmsterdamStudents = Roles.Where(r => r.description == "Student") .SelectMany(r => r.Person) .Intersect ( Locations .Where(l=> l.description == "Amsterdam") .SelectMany(l=>l.Person) ).ToList();
这有点冗长.但这会生成干净的SQL查询并且运行良好.
在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)
您可能希望测试哪个版本的数据速度更快.
祝好运.
朱利亚诺·莱姆斯