2012-07-24 20 views
7

Entity Framework/LINQを使用して、以下の点について助けが必要です。接合テーブルを照会する方法

データベースには、PersonIdというID列を持つPeopleテーブルがあります。 SkillIdのID列を持つスキルテーブルもあります。これらの2つは、独自の識別列PersonSkillsId、PersonIdを参照する外部列、およびSkillIdを参照する外部列を持つ3番目の表PeopleSkillsを介して接続されます。

私が作成しようとしているメソッドには、探しているスキルがいくつでも含まれるList型のパラメータが渡されます。メソッドは、入力パラメータリスト内のすべてのスキルにリンクされているリストを返す必要があります。スキルリストにすべてのスキルがない人を除外するリストを作成するにはどうすればよいですか?

私が抱えている問題は、SQLの経験がほとんどないことです。私は他の多くのプログラミング経験を持っていますが、SQLはいつも私のために少し荒いです。私はJoinを使うことを考えましたが、それはうまくいかないでしょう。すなわち、私の人物がスキルA & Bを有し、検索リストがB & Cの要素を有する場合、参加はBにそれらをマッチさせ、その人を返す。私はこの人が両方とも持っていないので除外する必要があります。& C.

スキルリストとフィルターを作成することについても考えましたが、それは醜いようです。これはちょうどLINQが処理するためにリストを使用して別のリストを照会し、そこには洗練された解決策があるべき問題のようです。

+1

私はこれをいくつか考えておきたいと思います。他の人がまだそうしていない場合は、包括的な回答で24時間以内にお返事します。 –

答えて

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

どちらの回答も私にはかなりわかりましたが、これは私が想像していたエレガントで簡単な方法です。ブリリアント。 –

1

私は、Linq to Entitiesの代わりにLinq-to-SQLを使用するLinqPadを使用しましたが、コンセプトは同じである必要があります。

まず、テストに使用したデータ。

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

ありがとうございます。私は決して思いつきませんでした! Anyを除く。 –

関連する問題