2012-07-24 51 views
7

使用實體框架/ LINQ,我需要以下幫助。如何查詢聯結表

該數據庫有一個PeopleId的標識列的人員表。還有一個SkillId身份欄的技能表。這兩個通過第三個PeopleSkills表連接,PeopleSkills具有自己的標識列PeopleSkillsId,一個引用PersonId的外部列和一個引用SkillId的外部列。

我試圖編寫的方法傳遞了一個List類型的參數,它包含我們正在尋找的任何數量的技能。該方法應返回一個鏈接到輸入參數列表中所有技能的列表。我如何建立一個排除任何沒有技能列表中所有技能的人的列表?

我遇到的問題是我有很少的SQL經驗。我有很多其他的編程經驗,但SQL對我來說總是有點粗糙。我想過使用Join,但這不起作用。即如果我的人有技能A & B,並且搜索列表包含元素B & C,則加入會在B上匹配他們並返回該人員。我需要排除這個人,因爲他沒有B & C.

我也想過關於迭代技能列表和構建過濾器,但看起來很醜。這看起來像是一個LINQ被構建來處理的問題,使用List來查詢另一個List,並且應該有一個優雅的解決方案。

+1

我想給出一些想法;如果其他人還沒有這樣做,我會在24小時內回覆給您一個全面的答案。 – 2012-07-24 19:19:47

回答

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)的條件的人。 (他們可能比給定的技能更多,但不會更少。)

+0

這兩個答案都顯示了我很多,但這是我設想的優雅簡單的方式。輝煌。 – 2012-07-25 01:06:19

1

我使用了LinqPad,它使用Linq-to-SQL而不是Linq來實體,但概念應該是相同的。

首先,我用來測試的數據。

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; 
+0

謝謝。我永遠不會想到!除了任何。 – 2012-07-24 21:36:15