7

Entity Framework/LINQ を使用して、次のことについて助けが必要です。

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

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

私が抱えている問題は、SQL の経験がほとんどないことです。他にもたくさんのプログラミング経験がありますが、SQL はいつも私にとって少し大雑把です。Join を使用することを考えましたが、うまくいきません。つまり、私の人がスキル A と B を持っていて、検索リストに B と C の要素がある場合、結合は B でそれらに一致し、人を返します。この人は B と C の両方を持っていないので、除外する必要があります。

スキル リストを反復処理してフィルターを構築することも考えましたが、それは見苦しく思えます。これは、List を使用して別の List を照会するために LINQ が処理するように構築された問題のように思われ、エレガントな解決策があるはずです。

4

2 に答える 2

2

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;
于 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 に答える