7

使用实体框架/LINQ,我需要以下帮助。

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

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

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

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

4

2 回答 2

2

我用的是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;
于 2012-07-24T20:34:31.293 回答
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)条件的人。(他们可能拥有比给定技能更多的技能,但不会更少。)

于 2012-07-24T21:55:06.497 回答