2010-01-14 18 views
11

Estoy tratando de convertir una vieja consulta Sql en Linq con Entity Framework aquí.Operador "IN" en Linq

Estaba utilizando el operador IN con una colección de elementos. La consulta fue algo así:

SELECT Members.Name 
FROM Members 
WHERE Members.ID IN (SELECT DISTINCT ManufacturerID FROM Products WHERE Active = 1) 
ORDER BY Members.Name ASC 

Desde el retorno de la subconsulta no es una sola cadena, sino una colección de cadenas no puedo usar el método String.Contains().

pensé en hacer algo como:

var activeProducts = (
from products in db.ProductSet 
where product.Active == true 
select product.ManufacturerID); 

y luego

var activeMembers = (
from member in db.ContactSet 
where member.ID.ToString().Contains(activeProducts)); 

pero se detiene en la contiene diciendo que tiene argumentos válidos ... No puedo seleccionar porque activeProducts.ManufacturerID Obviamente, la propiedad no está allí ya que devuelve un IQueryable ...

En pocas palabras, lo que estoy tratando de hacer aquí es devolver una lista de miembros que tienen al menos uno producto activo.

¿Alguna pista?

[editar]

Aquí está el código de consulta completo ... He intentado con la contiene en la segunda expresión, LINQ no parece que les gusta:

Server Error in '/' Application. LINQ to Entities does not recognize the method 'Boolean Contains[String](System.Linq.IQueryable``1[System.String], System.String)' method, and this method cannot be translated into a store expression.

var activeProduct =(from product in Master.DataContext.ProductSet 
         where product.Active == true 
          && product.ShowOnWebSite == true 
          && product.AvailableDate <= DateTime.Today 
          && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
         select product.ManufacturerID.ToString()); 

    var activeArtists = from artist in Master.DataContext.ContactSet 
         where activeProduct.Contains(artist.ID.ToString()) 
         select artist; 

    NumberOfArtists = activeArtists.Count(); 

    artistsRepeater.DataSource = activeArtists; 
    artistsRepeater.DataBind(); 

[Más información] ManufacturerID es un GUID que puede contener nulos aparentemente ...

Por alguna razón, la clase ContactSet no contiene un En referencia a los productos, supongo que tendré que hacer una consulta de combinación, no hay pistas aquí.

Respuesta

12
var activeMembers = (
from member in db.ContactSet 
where activeProducts.Select(x=>x.ID).Contains(member.ID)); 
5

Probar where activeProducts.Contains(member.ID).
EDIT: ¿Lo intentó sin ningún ToString s?

+0

No funciona, tiene un error Linq. – Erick

+0

Sí, y a Linq todavía no le gusta, ¿acabo de descubrir que ManufacturerID es un Guid? (Nullable) ... si hago un 'seleccione ManufacturerID.Valor' Tengo esto: LINQ to Entities no reconoce el método 'Boolean Contiene [Guid] (System.Linq.IQueryable'1 [System.Guid], System.Guid)' método, y este método no se puede traducir a una tienda expresión. – Erick

+0

¿Es esto tan eficiente como el operador IN? – tofutim

0

lugar de esto:

var activeMembers = (
from member in db.ContactSet 
where member.ID.ToString().Contains(activeProducts)); 

Prueba esto:

var activeMembers = (
from member in db.ContactSet 
where activeProducts.Contains(member.ID)); 
+0

Intentó, a Linq no pareció gustarle en realidad. – Erick

+0

¿Qué pasó exactamente cuando lo intentó? – SLaks

+0

El error está allí en la edición =) – Erick

0

¿Qué pasa si se cambia la declaración (no probado)?

where activeProducts.Contains(member.ID) 
0

¿Qué tal esto ...

var activeProducts = (
from products in db.ProductSet 
where product.Active == true 
select product.ManufacturerID); 

var activeMembers = (
from member in db.ContactSet 
where activeProducts.Contains(member.ID.ToString())); 
+0

No funciona realmente. – Erick

+0

Creo que este cambio podría hacer que funcione ... var = (activeProducts de productos en db.ProductSet donde product.Active == true seleccionar product.ManufacturerID); var activeMembers = ( desde miembro en db.ContactSet donde activeProducts.Select (x => x.id) .Contains (member.ID.ToString())); – spadelives

+0

'product.Active == true' es un poco redundante ¿no? Solo 'product.Active' es suficiente. – Askolein

2

usted puede hacerlo en una consulta:

var q = from member in db.ContactSet 
     where member.Products.Any(p => p.IsActive) 
     select member; 
+0

Tuve que simplificar la declaración, pero hay más condiciones para el "dónde" ... Edité mi publicación para incluir el código completo, de hecho. – Erick

+1

Aún puede hacerlo en una consulta. Mueva la cláusula 'where' completa a la llamada' Any'. – SLaks

+0

No hay ningún vínculo entre ContactSet y ProductSet (por ejemplo, cómo me encanta la modificación de software de terceros), supongo que tendré que hacer una consulta de combinación ... – Erick

0

Un ayudante o método de extensión funcionará bien cuando se consulta contra objetos en memoria. Pero contra una base de datos SQL, su código LINQ se compilará en un árbol de expresiones, se analizará y se traducirá en un comando SQL. Esta funcionalidad no tiene ningún concepto de métodos de extensión personalizados o métodos de otros objetos como .Contains(...).

Aunque Microsoft podría implementarlo fácilmente en la funcionalidad estándar de LINQ-To-SQL. Pero mientras ellos no quieran, estamos indefensos siempre que no sea una funcionalidad de código abierto.

Todo lo que puede hacer es crear su propio QueryProvider que va en contra de una base de datos SQL. Pero será difícil y sería solo por esa única característica in que te hace falta.

Sin embargo, si realmente quieres ir por ese camino, divertirse: LINQ: BUILDING AN IQUERYABLE PROVIDER SERIES

0

fin he conseguido codificar algo realmente feo, pero que realmente funciona! (Lol)

var activeProduct =(from product in Master.DataContext.ProductSet 
         where product.Active == true 
          && product.ShowOnWebSite == true 
          && product.AvailableDate <= DateTime.Today 
          && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
         select product.ManufacturerID).Distinct(); 

    var artists = from artist in Master.DataContext.ContactSet 
         select artist; 

    List<Evolution.API.Contact> activeArtists = new List<Evolution.API.Contact>(); 

    foreach (var artist in artists) 
    { 
     foreach(var product in activeProduct) 
     { 
      if (product.HasValue && product.Value == artist.ID) 
       activeArtists.Add(artist); 
     } 
    } 

    NumberOfArtists = activeArtists.Count(); 

    artistsRepeater.DataSource = activeArtists; 
    artistsRepeater.DataBind(); 
0
var q = (from p in db.DOCAuditTrails 
     where p.ActionUser == "MyUserID" 
     && p.ActionTaken == "Not Actioned" 
     && p.ActionDate > DateTime.Parse("2011-09-13") 
      select p.RequisitionId).Distinct(); 

var DocAuditResults = db.DOCAuditTrails.Where(p 
    => q.ToArray().Contains(p.RequisitionId)); 
1

Qué tal esto:

from m in members 
where products.FirstOrDefault(prod => prod.IsActive == 1 && prod.Id == m.Id) != null 
select m; 

se pueden encadenar cualquier número de condiciones exigidas en la cláusula where usando & &

Ash ..

2
from m in members 
where products.Any(p => p.Active && p.ManufacturerID == m.ID) 
select m 

o

from m in members 
join p in products on m.ID equals p.ManufacturerID 
where p.Active 
select m 
0

Sin conocer las asignaciones exactas que es difícil saber qué se puede hacer y lo que no puede. Asumiré que no hay ningún casting involucrado. En primer lugar, debe recordar que todo en el árbol de expresiones de Linq debe tener un equivalente en SQL. Como han señalado algunos otros, tiene un object.ToString() en sus sentencias de Linq.

Sin embargo, parece que lo que la gente ha olvidado mencionar es que tiene DOS usos de object.ToSting(), los cuales deben ser eliminados.

También crearía una variable extra para cambiar el tipo de captura del cierre para que sea explícitamente DataContext (ya que la instrucción Linq es como una lambda, y se evalúa con retraso. Necesitará tomar toda la variable maestra. declaró que todo en su Linq debe tener un equivalente en SQL. Dado que el Maestro no puede existir en SQL, no existe ninguna propiedad/columna/mapeo de DataContext para el tipo de Maestro).

var context = Master.DataContext; 
var activeProduct = from product in context.ProductSet 
        where product.Active == true 
         && product.ShowOnWebSite == true 
         && product.AvailableDate <= DateTime.Today 
         && (product.DiscontinuationDate == null || product.DiscontinuationDate >= DateTime.Today) 
        select product.ManufacturerID; 

var activeArtists = from artist in context.ContactSet 
        where activeProduct.Contains(artist.ID) 
        select artist; 

Espero que los cambios anteriores funcionen para usted.

En muchos casos, los problemas con Linq a ORM pueden remontarse a su Linq Expression capturando una clase no primitiva (DateTime, int, string, etc.) y no basada en ORM (DataContext/EntityObject, etc.). El otro gran inconveniente es el uso de funciones y operadores que no están expuestos por el ORM (es posible asignar funciones definidas por el usuario a la función .net a través del ORM, pero no lo recomendaría debido a problemas de indexación).