【问题标题】:How do I query a junction table如何查询联结表
【发布时间】:2012-07-22 22:52:18
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 我想考虑一下;如果其他人还没有这样做,我会在接下来的 24 小时内给你一个全面的答复。

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


【解决方案1】:

这可以工作:

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)。 (他们可能比给定的技能更多,但不能更少。)

【讨论】:

  • 两个答案都向我展示了很多,但这是我所设想的优雅简单的方式。太棒了。
【解决方案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;

【讨论】:

  • 谢谢。我永远不会想出!任何除外。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多