2012-07-24 8 views
7

Korzystanie z Entity Framework/LINQ, potrzebuję pomocy w następujących sprawach.Jak wykonać kwerendę tabeli skrzyżowań

Baza danych zawiera tabelę osób z kolumną tożsamości PersonId. Istnieje również tabela umiejętności z kolumną tożsamości SkillId. Te dwa są połączone za pośrednictwem trzeciej tabeli PeopleSkills, która ma własną kolumnę tożsamości PeopleSkillsId, obcą kolumnę odwołującą się do PersonId i obcą kolumnę odwołującą się do SkillId.

Metoda, którą próbuję zapisać, jest przekazywana jako parametr typu List, który zawiera dowolną liczbę umiejętności, których szukamy. Metoda powinna zwrócić Listę, która jest połączona z wszystkimi umiejętnościami na liście parametrów wejściowych. Jak zbudować listę, która wyklucza kogokolwiek bez wszystkich umiejętności z listy Umiejętności?

Problem polega na tym, że mam bardzo mało doświadczenia SQL. Mam wiele innych doświadczeń programistycznych, ale SQL jest zawsze dla mnie trochę trudny. Myślałem o użyciu Join, ale to nie zadziała. tj. jeśli moja osoba ma umiejętności A & B, a lista wyszukiwania zawiera elementy B & C, połączenie będzie dopasowane do nich na B i zwróci osobę. Potrzebuję tej osoby do wykluczenia, ponieważ on nie ma zarówno B & C.

Też myślałem o iteracji przez listę umiejętności i budowaniu filtra, ale to wydaje się brzydkie. Wydaje się, że jest to problem polegający na tym, że LINQ został zbudowany do obsługi, używając Listy do odpytywania na innej Liście i że powinno być eleganckie rozwiązanie.

+1

Chciałbym dać ci to trochę do myślenia; W ciągu 24 godzin skontaktuję się z Tobą, udzielając wyczerpującej odpowiedzi, jeśli ktoś jeszcze tego nie zrobił. –

Odpowiedz

0

To może działać:

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(); 
} 

Daj mi ludzi, którzy spełniają warunek, że istnieje wszystko podane umiejętności (Any) na liście umiejętności tych ludzi. (Mogą mieć więcej niż podane umiejętności, ale nie mniej.)

+0

Obie odpowiedzi pokazały mi sporo, ale jest to elegancko prosty sposób, jaki sobie wyobrażałem. Znakomity. –

1

Użyłem LinqPad, który używa Linq-SQL zamiast Linq do Entities, ale koncepcje powinny być takie same.

Najpierw dane, które testowałem.

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 rozwiązanie.

//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

Dziękuję. Nigdy bym nie wpadł! Z wyjątkiem Any. –