2012-07-24 14 views
7

Utilizando Entity Framework/LINQ, necesito ayuda con lo siguiente.Cómo consulto una tabla de unión

La base de datos tiene una tabla de personas con una columna de identidad de PersonId. También hay una tabla de habilidades con una columna de identidad de SkillId. Estos dos están conectados a través de una tercera tabla PeopleSkills que tiene su propia columna de identidad PeopleSkillsId, una columna extranjera que hace referencia a PersonId y una columna extranjera que hace referencia a SkillId.

El método que estoy tratando de escribir se pasa un parámetro del tipo Lista que contiene cualquier cantidad de habilidades que estamos buscando. El método debe devolver una Lista que esté vinculada a todas las habilidades en la lista de parámetros de entrada. ¿Cómo construyo una lista que excluye a cualquier persona sin todas las habilidades en la lista de habilidades?

El problema que tengo es que tengo muy poca experiencia en SQL. Tengo mucha otra experiencia en programación, pero SQL siempre es un poco difícil para mí. Pensé en usar una unión, pero eso no va a funcionar. es decir, si mi persona tiene las habilidades A & B, y la lista de búsqueda tiene elementos para B & C, una unión los uniría en B y devolvería a la persona. Necesito que esta persona sea excluida porque él no tiene ambos B & C.

También pensé en iterar a través de la lista de habilidades y construir un filtro, pero eso parece feo. Esto simplemente parece un problema que LINQ fue creado para manejar, usando una lista para consultar otra lista, y que debería haber una solución elegante para.

+1

Me gustaría pensar en esto; Me pondré en contacto con usted dentro de las próximas 24 horas con una respuesta completa, si alguien más no lo ha hecho. –

Respuesta

0

Esto podría funcionar:

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

Dame las personas que cumplan con la condición de que existen todas habilidades dadas (Any) en la lista de habilidades de las personas. (Pueden tener más que las habilidades dadas, pero no menos.)

+0

Ambas respuestas me mostraron bastante, pero esta es la manera elegantemente simple que estaba imaginando. Brillante. –

1

Usé LinqPad, que utiliza Linq-to-SQL en lugar de Linq para Entidades, pero los conceptos deben ser los mismos.

Primero, los datos que utilicé para probar.

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) 

Y la solución.

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

Gracias. ¡Nunca me hubiera ocurrido! Excepto Any. –

Cuestiones relacionadas