2010-12-10 65 views
0

Pour un projet utilisant LINQ to Entities 4.0, j'ai un paramètre dans lequel je dois retourner une requête avec une valeur (constante) ajoutée au préalable. Si je l'étais le codage dans SQL, il ressemblerait à quelque chose comme ceci:Comment créer une méthode d'extension Prepend pour IQueryable <T> qui est compatible avec Linq to Entities 4.0?

select 0 as ID, 'default' as Name 
union 
select ID, Name from X 

Pour ce projet, je voudrais créer une méthode d'extension générique IQueryable qui accepte une valeur constante renvoie une requête avec la valeur constante préfixé comme son résultat. Le processus ne doit pas déclencher l'énumération, car je ne souhaite pas que la requête déclenche un accès à la base de données à moins que l'autre code de l'application n'énumère la requête.

Idéalement, j'aimerais que le résultat IQueryable puisse être joint à d'autres requêtes Linq to Entities et traité par le fournisseur L2E.

J'ai essayé quelques variantes, mais je me suis rendu compte qu'elles allaient déclencher l'énumération au lieu d'ajouter à la requête. Ma dernière tentative étend la requête sans l'énumération (comme on le souhaite), mais renvoie une erreur.

public static IQueryable<T> Prepend<T>(
     this IQueryable<T> query 
     , T value 
     ) 
    { 
     return query 
      .Where(t => false).DefaultIfEmpty(value) 
      .Concat(query); 
    } 

L'erreur est, « Impossible de créer une valeur constante de type « OCEAN.Business.Pocos.ExclusionIncomeType » Seulement primitive types ('tels que Int32, String et Guid') sont pris en charge dans ce contexte. ".

J'ai essayé de rechercher des concepts similaires, y compris l'ajout d'une valeur, mais en vain.

Des idées?

+0

Avez-vous essayé d'utiliser un 'Union' réelle? 'query.Union (new [] {valeur})'? Je sais que Linq-to-SQL n'aime pas ça, mais peut-être que Linq-to-Entities peut le gérer? – bdukes

Répondre

0

réponse finale:

private static IEnumerable<T> PrependEnumerator<T>(this IEnumerable<T> sequence, T value) 
    { 
     yield return value; 
     foreach (var item in sequence) 
     { 
      yield return item; 
     } 
    } 

    public static IQueryable<T> Prepend<T>(
     this IQueryable<T> query 
     , T value 
     ) 
    { 
     return query.PrependEnumerator(value).AsQueryable(); 
    } 
1

Vous pouvez utiliser un iterator pour créer une nouvelle IEnumerable<T> instance qui retourne votre valeur par défaut premier:

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> sequence, T value) 
{ 
    yield return value; 
    foreach (var item in sequence) 
    { 
     yield return item; 
    } 
} 

Cela va créer un recenseur qui va d'abord retourner votre article par défaut, puis énumérer la requête.

+0

Cela semble prometteur. Idéalement, j'aimerais que le résultat IQueryable puisse être joint à d'autres requêtes Linq to Entities et traitable par le fournisseur L2E. Cependant, cela permettrait de résoudre mon besoin de base. – BrianCooksey

+0

À la réflexion, ce n'est techniquement pas une correspondance puisque IEnumerable n'implémente pas IQueryable (bien que l'inverse soit vrai). Cependant, je pourrais être en mesure de résoudre ce problème. – BrianCooksey

+0

// qui m'a eu à mi-chemin. solution finale: private static IEnumerable PrependEnumerator (cette séquence IEnumerable , valeur T) { rendement de retour; foreach (var article en séquence) { rendement rendement; }} IQueryable public static Prepend ( cette IQueryable requête , T valeur ) { query.PrependEnumerator de retour (valeur).AsQueryable(); } – BrianCooksey

0
private static IEnumerable<T> PrependEnumerator<T>(
    this IEnumerable<T> sequence, 
    T value 
    ) 
{ 
    yield return value; 
    foreach (var item in sequence) { yield return item; } 
} 
public static IQueryable<T> Prepend<T>( 
    this IQueryable<T> query , 
    T value 
    ) 
{ 
    return query.PrependEnumerator(value).AsQueryable(); 
}