如何查询联结表

时间:2012-07-24 15:14:31

标签: .net linq entity-framework junction-table

使用Entity Framework / LINQ,我需要以下帮助。

数据库有一个People表,其Person标识列为PersonId。还有一个Skills表,其标识列为SkillId。这两个通过第三个表PeopleSkills连接,这个表有自己的标识列PeopleSkillsId,引用PersonId的外部列和引用SkillId的外部列。

我尝试编写的方法是传递一个List类型的参数,该参数包含我们正在寻找的任何技能。该方法应返回链接到输入参数列表中所有技能的List。如何建立一个排除任何没有技能列表中所有技能的人的列表?

我遇到的问题是我的SQL经验非常少。我确实有很多其他编程经验,但SQL对我来说总是有点粗糙。我想过使用Join,但那不行。即如果我的人有技能A& B,搜索列表中包含B& B的元素。 C,一个连接将在B上匹配它们并返回该人。我需要将这个人排除在外,因为他没有B& B C.

我还想过迭代技能列表并构建过滤器,但这看起来很难看。这似乎是LINQ构建要处理的问题,使用List来查询另一个List,并且应该有一个优雅的解决方案。

2 个答案:

答案 0 :(得分:1)

我使用LinqPad,它使用Linq-to-SQL而不是Linq to Entities,但概念应该是相同的。

首先,我用来测试的数据。

create table People (PersonID int, Name varchar(100))
create table Skills (SkillID int, Skill varchar(100))
create table PeopleSkills (PeopleSkillsID int, PersonID int, SkillID int)

insert People values (1,'Bert'),(2,'Bob'),(3,'Phil'),(4,'Janet')
insert Skills values (1,'C#'),(2,'Linq'),(3,'SQL')
insert PeopleSkills values (1,1,1),(2,1,2),(3,1,3),(4,2,1),(5,2,3),(6,3,2),(7,3,3),(8,4,1),(9,4,2),(10,4,3)

解决方案。

//I don't know how you are specifying your list of skills; for explanatory purposes
//I just generate a list.  So, our test skill set is C#, Linq, and SQL.
//int? is used because of LinqToSQL complains about converting int? to int
var skills = new List<int?>(){1,2,3}; 
//This initial query is also a small bow to LinqToSQL; Really I just wanted a plain
//List so that the Except and Any clauses can be used in the final query.
//LinqToSQL can apparently only use Contains; that may or may not be an issue with
//LinqToEntities.  Also, its not a bad idea to filter the people we need to look at
//in case there are a large number anyway.
var peopleOfInterest = PeopleSkills.Where( p => skills.Contains(p.SkillID)).ToList();   

//Final query is relatively simple, using the !x.Except(y).Any() method to 
//determine if one list is a subset of another or not.
var peopleWithAllSkills = 
    //Get a distinct list of people
    from person in peopleOfInterest.Select( p=>p.PersonID).Distinct()
    //determine what skills they have
    let personSkills = peopleOfInterest.Where(x=>x.PersonID == person).Select(x=>x.SkillID)
    //check to see if any of the skills we are looking for are not skills they have
    where !skills.Except(personSkills).Any()
    select person;

答案 1 :(得分:0)

这可行:

public List<Person> GetPeopleWithAllSkills(List<Skill> skills)
{
    var skillIds = skills.Select(s => s.SkillId);

    return context.People.Where(
        p => skillIds.All(id => p.PeopleSkills.Any(ps => ps.SkillId == id)))
        .ToList();
}

在这些人的技能列表中,向我提供满足所有给定技能的条件的人(Any)。 (他们可能拥有的技能不仅仅是给定的技能,但不能少于。)