2010-08-19 5 views
6

Je souhaite renvoyer un ensemble d'entités ayant un ID et un ID contenus dans une liste ou un tableau d'ID à l'aide de LINQ et de Data Services. Je sais comment utiliser LinqToEF, mais je ne sais pas comment utiliser Data Services ou utiliser les conventions de requêtes OData.Sélectionnez les entités où ID dans un tableau int - WCF Data Services, LINQ

Ma pensée est que je fais quelque chose comme:

int[] intArray = {321456, 321355, 218994, 189232}; 
var query = (from data in context.Entity 
      where intArray.contains(data.ID) 
      select data); 

Est-il possible d'accomplir en utilisant Data Services/OData? Je sais que je pourrais probablement le pirater avec une opération de service mais je préférerais ne pas faire cela.

Cheers.

Répondre

8

Actuellement, OData (le protocole sous-jacent) ne prend pas en charge l'opération Contient. C'est pourquoi la bibliothèque cliente ne traduit pas la requête ci-dessus. Les utilisateurs utilisent essentiellement deux méthodes pour surmonter cette limitation: 1) Utilisez les opérations de maintenance comme indiqué. 2) Construire dynamiquement une clause where qui utilise des comparaisons simples pour comparer la valeur à chaque élément du tableau. Donc, si le tableau contient 1, 2, 3, l'où serait data.ID == 1 || data.ID == 2 || data.ID == 3 La solution n ° 2 est sympa car il s'agit uniquement d'un changement côté client. L'inconvénient est que cela ne fonctionne que pour les petites baies. Si le tableau contient trop d'éléments, l'expression devient trop longue et cela entraîne toutes sortes de problèmes. La solution n ° 1 n'a pas le problème de taille, mais vous devez fournir l'opération sur le serveur.

+0

"Construire une clause where dynamiquement qui utilise des comparaisons simples comparer la valeur à chaque élément du tableau "- pouvez-vous donner un exemple. –

+0

Exemple serait plutôt long - vous pouvez probablement rechercher "LINQ dynamique" et autres. La méthode de bas niveau consiste à utiliser la classe Expression et son API pour construire la requête LINQ par programmation. –

0

Merci hommes vous m'a vraiment aidé :) :)

Je l'ai fait comme Vitek Karas dit.

1) Télécharger la bibliothèque requête dynamique Cocher cette link

Pas besoin de le lire il suffit de télécharger la bibliothèque de recherche dynamique

2) Vérifiez le projet nommé DynamicQuery. Vous y trouverez une classe nommée Dynamic.cs. Copiez-le dans votre projet

3) Générez votre projet (Si vous utilisez silverlight, une erreur indiquant que ReaderWriterLock n'est pas trouvé apparaîtra.Ne vous inquiétez pas. Il vous suffit de commenter ou de supprimer les lignes qui font des erreurs (il y a juste 6 ou 7 lignes qui erreurs))

4) Tout ce que vous devez faire tout à l'heure d'écrire votre requête Exemple: ordersContext.CLIENTS.Where(" NUMCLI > 200 || NUMCLI < 20");

Tout est fait. Si vous devez utiliser la méthode 'Contient' vous devez simplement écrire une méthode qui parcourra votre tableau et retourner la chaîne que votre requête utilisera.

private string MyFilter() 
{ string st = ""; 

     foreach(var element in myTab) 
     { 
       st = st + "ThePropertyInTheTable =" + element + "||"; 
     } 

     return st; 
} 

J'espère que vous me comprenez et que j'ai aidé quelqu'un :)

+0

Cette solution a provoqué un problème lorsque la demande était trop longue. J'ai donc trouvé une autre solution en utilisant AddQueryOption et en utilisant $ filter comme ceci: DataServiceQuery ordersQuery = (DataServiceQuery ) this.context.CLIENTS.AddQueryOption ("$ filter", MyFilter()); – ihebiheb

+0

N'utilisez pas les majuscules ET. cela mène à et erreur. utiliser et non ET. – ihebiheb

3

Voici ma réalisation de laquelle() Méthode pour filtrer la collecte IQueryable par un ensemble d'entités sélectionnées:

public static IQueryable<T> WhereIn<T,TProp>(this IQueryable<T> source, Expression<Func<T,TProp>> memberExpr, IEnumerable<TProp> values) where T : class 
    { 
     Expression predicate = null; 
     ParameterExpression param = Expression.Parameter(typeof(T), "t"); 

     bool IsFirst = true; 

     // Create a comparison for each value eg:     
     // IN: t => t.Id == 1 | t.Id == 2     

     MemberExpression me = (MemberExpression) memberExpr.Body; 
     foreach (TProp val in values) 
     { 
      ConstantExpression ce = Expression.Constant(val); 


      Expression comparison = Expression.Equal(me, ce); 

      if (IsFirst) 
      { 
       predicate = comparison; 
       IsFirst = false; 
      } 
      else 
      { 
       predicate = Expression.Or(predicate, comparison); 
      } 
     } 

     return predicate != null 
      ? source.Where(Expression.Lambda<Func<T, bool>>(predicate, param)).AsQueryable<T>() 
      : source; 
    } 

Et l'appel de cette méthode ressemble à:

IQueryable<Product> q = context.Products.ToList(); 

var SelectedProducts = new List<Product> 
{ 
    new Product{Id=23}, 
    new Product{Id=56} 
}; 
... 
// Collecting set of product id's  
var selectedProductsIds = SelectedProducts.Select(p => p.Id).ToList(); 

// Filtering products 
q = q.WhereIn(c => c.Product.Id, selectedProductsIds); 
+2

Très bien. Il donne cependant un résultat inattendu avec un tableau vide en entrée. Vous ne vous attendez pas à ce que rien ne se trouve dans ce tableau vide, ce qui ne donne aucun résultat, mais renvoie tout. Dans cet esprit, j'ai changé la déclaration de retour à: return predicate! = Null ? source.Where (Expression.Lambda > (prédicat, param)). AsQueryable () : source.Where (x => false) .AsQueryable (); –