2012-07-24 19 views
7

Utilizzando Entity Framework/LINQ, ho bisogno di aiuto con quanto segue.Come si esegue una query su una tabella di giunzione

Il database ha una tabella di persone con una colonna di identità di PersonId. C'è anche una tabella delle abilità con una colonna di identità di SkillId. Questi due sono collegati tramite una terza tabella PeopleSkills che ha la propria colonna Identity PeopleSkillsId, una colonna straniera che fa riferimento a PersonId e una colonna straniera che fa riferimento a SkillId.

Il metodo che sto cercando di scrivere è passato un parametro di tipo List che contiene un numero qualsiasi di competenze che stiamo cercando. Il metodo dovrebbe restituire un elenco che è collegato a tutte le abilità nell'elenco dei parametri di input. Come faccio a creare un elenco che escluda chiunque senza tutte le abilità nella lista Abilità?

Il problema che sto avendo è che ho pochissima esperienza SQL. Ho un sacco di altre esperienze di programmazione, ma SQL è sempre un po 'complicato per me. Ho pensato di usare un join, ma non funzionerà. Ad esempio, se la mia persona ha competenze A & B e l'elenco di ricerca contiene elementi per B & C, un join li abbinerebbe a B e restituirà la persona. Ho bisogno che questa persona sia esclusa perché non ha entrambi B & C.

Ho anche pensato di passare attraverso la lista delle abilità e di costruire un filtro, ma questo sembra brutto. Questo sembra un problema che LINQ è stato creato per gestire, utilizzando un elenco per interrogare un altro elenco e che dovrebbe esserci una soluzione elegante.

+1

Mi piacerebbe dare un po 'di riflessione; Ti ricontatterò entro le prossime 24 ore con una risposta esauriente, se qualcun altro non l'ha già fatto. –

risposta

0

Questo potrebbe funzionare:

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

Dammi le persone che soddisfano la condizione che tutti dato competenze esistono (Any) nella lista delle competenze di quelle persone. (Potrebbero avere più delle competenze fornite ma non di meno.)

+0

Entrambe le risposte mi hanno mostrato un po ', ma questo è il modo elegante e semplice che stavo immaginando. Brillante. –

1

Ho usato LinqPad, che usa Linq-to-SQL anziché Linq in Entità, ma i concetti dovrebbero essere gli stessi.

In primo luogo, i dati che ho usato per testare.

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) 

E la soluzione.

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

Grazie. Non mi sarei mai inventato! Tranne Qualsiasi. –

Problemi correlati