Entity Framework: unirse a una lista

Necesito recuperar una lista de entidades de mi base de datos que coincida con una lista de elementos en una lista simple (no EF). ¿Es esto posible con Entity Framework 4.1?

Ejemplo:

var list = new List<string> { "abc", "def", "ghi" };
var items = from i in context.Items
            where list.Contains(i.Name)
            select i;

Esto funciona muy bien para devolver filas que coinciden con una propiedad, pero en realidad tengo una propiedad más compleja:

var list = new List<Tuple<string, string>>
{
    new Tuple<string,string>("abc", "123"),
    new Tuple<string,string>("def", "456")
};

// i need to write a query something like this:
var items = from i in context.Items
where list.Contains(new Tuple<string,string>(i.Name, i.Type))
select i;

Sé que no es válido porque dirá que debe ser un tipo primitivo, pero ¿hay alguna forma de hacer lo que estoy tratando de lograr o tendré que recurrir a un procedimiento almacenado?

preguntado el 08 de noviembre de 11 a las 16:11

3 Respuestas

Debe dividirlo en subpropiedades. Por ejemplo, algo como (es posible que esto no se compile, no puedo probar en este momento, pero debería darte algo con lo que trabajar):

var items = from i in context.Items 
where list.Select(x => x.Item1).Contains(i.Name) 
   && list.Select(x => x.Item2).Contains(i.Type)
select i; 

respondido 08 nov., 11:20

No funciona. Errores al intentar ejecutar. No se puede crear un valor constante de tipo Test.Pair. En este contexto, solo se admiten tipos primitivos. - Despedir

Debe pensar en cómo se vería el SQL resultante, esto sería difícil de hacer directamente en SQL.

Mi sugerencia sería que divida un campo de las tuplas y use esto para reducir la lista de resultados, recupere el resultado de la consulta y luego vuelva a filtrar para que coincida con una de las tuplas, por ejemplo

var list = new List<string> { "abc", "def" };
var list2 = new List<Tuple<string, string>>
{
  new Tuple<string,string>("abc", "123"),
  new Tuple<string,string>("def", "456")
};
var items = (from i in context.Items
        where list.Contains(i.Name)
        select i)
        .AsEnumerable()
        .Where(i => list2.Any(j => j.val1 == i.Name && j.val2 == i.Type);

respondido 08 nov., 11:20

Realmente no es una solución viable para mi caso. El nombre y el tipo básicamente forman una clave única para mí. El nombre por sí solo devolvería demasiadas filas. Creo que tendré que crear un procedimiento almacenado y usar un parámetro con valores de tabla. - Despedir

O puede escribir sus tuplas en una tabla temporal y hacer una unión a la base de datos - James Ellis-Jones

Tienes pocas opciones:

1) Por supuesto, podría escribir un procedimiento almacenado para hacer lo que necesita y llamarlo.

2) Puede leer la tabla en la memoria y luego consultar la lista en la memoria ... de esa manera no tiene que usar primitivas:

var items = from i in context.Items.ToList()
            where list.Contains(new Tuple<string, string>(i.Name, i.Type))
            select i;

3) También puede convertir su consulta para usar primitivas para lograr el mismo objetivo:

var items = from i in context.Items
            join l in list
            on new { i.Name, i.Type } equals 
                new { Name = l.Item1, Type = l.Item2 }
            select i;

Yo optaría por la segunda opción siempre que la mesa no sea extremadamente grande. De lo contrario, vaya con el primero.

respondido 08 nov., 11:20

@Dismissile - ¿Qué no funciona? ¿No son los resultados esperados o es un error? - Justin Niessner

@JustinNiessner Da error al intentar ejecutar la consulta. Dice que necesita un tipo primitivo. No creo que sea lo suficientemente inteligente como para enviar una lista de pares de cadenas / cadenas a la consulta. - Despedir

System.NotSupportedException no se controló Mensaje = No se pudo crear un valor constante de tipo 'Test.Pair'. En este contexto, solo se admiten los tipos primitivos ('como Int32, String y Guid'). - Despedir

@JustinNiessner Creo que tendrá que ser el número uno. Hay demasiadas entidades para recuperar una lista en memoria y consultar a partir de eso. Creo que usaré un parámetro con valores de tabla para enviarlo al proceso almacenado, lo que debería facilitar la unión y obtener los resultados que necesito. - Despedir

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.