2011-10-12 13 views
37

Tengo un servicio OData donde intento filtrar por una lista de ID; el equivalente SQL sería algo así como:OData consulta "donde ID en la lista"

SELECT * FROM MyTable WHERE TableId IN (100, 200, 300, 400) 

La propiedad que estoy tratando de filtrar se escribe como un Int32. He intentado lo siguiente, que me da un error "Operador 'añadir' 'incompatible con Edm.String' tipos de operando y 'Edm.Int32'":

string ids = ",100,200,300,400,"; 
from m in provider.Media where ids.Contains("," + t.media_id + ",") 

, así como

string ids = ",100,200,300,400,"; 
from m in provider.Media where ids.Contains("," + t.media_id.ToString() + ",") 

y

string ids = ",100,200,300,400,"; 
from m in provider.Media where ids.Contains("," + Convert.ToString(t.media_id) + ",") 

y

string ids = ",100,200,300,400,"; 
from m in provider.Media where ids.Contains(string.Concat(",", t.media_id, ",")) 

Como puede ver, actualmente estoy usando LINQ para consultar el servicio.

¿Hay alguna manera de hacer lo que intento, o estoy atascado construyendo un filtro de texto y usando AddQueryOption, y recorriendo la lista y agregando manualmente las cláusulas "o media_id eq 100"?

+1

https://gist.github.com/mausch/6893533 –

Respuesta

31

prueba este

var ids = new [] { 100, 200, 300 } ; 
var res = from m in provider.Media 
      from id in ids 
      where m.media_id == id 
      select m; 

hay una descripción completa sobre msdn en la consulta DataServices.

otro enfoque sería

var results = provider.Media 
    .AddQueryOption("$filter", "media_id eq 100"); 

y desde OData no soporta IN declaraciones que se van a plantear con la condición de filtro como éste

.AddQueryOption("$filter", "(media_id eq 100) or (media_id eq 200) or ..."); 

que se puede construir con lazo o LINQ Select y string.Join:

var ids = new [] { 100, 200, 300 }; 
var filter = string.Join(" or ", ids.Select(i=> $"(media_id eq {i})")); 
var results = provider.Media.AddQueryOption("$filter", filter); 

ACTUALIZACIÓN: Hay operación de filtro field=["a","b"], pero significa algo diferente.

Update2: En OData V4 hay expresiones lambda any y all, emparejado con arreglo literal ["a", "b"] podrían funcionar como in pero no fue capaz de llegar a ejemplo usando punto final v4 trabajar en OData.org

+0

Eso arroja un error: "Error al traducir la expresión Linq a URI: El método 'Seleccionar' no es compatible." Buena idea, sin embargo. – technophile

+0

eso es lo que esperaba. entonces su única opción es usar el segundo enfoque, que sería fácil en su caso cuando no sabe cuántos elementos de una lista tiene por adelantado – vittore

+0

Sí, el bucle con $ filter es lo que terminé haciendo. ¡Espero que nunca supere la limitación de longitud de URL! :-D – technophile

12

Expansión en respuesta vittore 's (de las cuales la segunda parte es la respuesta correcta), he escrito algo similar a la siguiente para un proyecto de demostración:

var filterParams = ids.Select(id => string.Format("(media_id eq {0})", id)); 
var filter = string.Join(" or ", filterParams); 
var results = provider.Media.AddQueryOption("$filter", filter).Execute().ToList(); 

no es elegante, y no querría usar esto para una gran lista de identificadores (> ~ 60), pero hará el truco.

0

Ampliando la sugerencia de MCattle si necesitamos más 50 o 60 ids, entonces es aconsejable hacerlo en 2 o más llamadas paralelas y agregarlas al diccionario simultáneo o algo similar a medida que obtengamos los resultados del servidor.Aunque esto aumenta la cantidad de llamadas al servidor, pero debido a que nos estamos moviendo lentamente al entorno de la nube, no debería ser un gran problema en mi opinión.

Cuestiones relacionadas