2010-11-11 19 views
1

J'ai le modèle suivant:Comment puis-je transmettre un prédicat <T> à la méthode Where() dans Linq to SQL?

+--------+ 
| Folder | 
+--------+ 
    | 1 
    | 
    | * 
+----------+   +---------+ 
| WorkItem |---------| Project | 
+----------+ *  1 +---------+ 

J'ai besoin de récupérer une liste de dossiers avec le nombre actuel de WorkItems.

Si j'ai spécifié un projet, je ne souhaite que le nombre d'éléments de travail dans chaque dossier associé au projet spécifié.

Si aucun projet n'est spécifié, il doit renvoyer le nombre total d'éléments de travail.

J'ai la Linq suivante au code SQL:

public interface IWorkItemCriteria { 
    int? ProjectId { get; } 
} 

public static IQueryable<Folder> GetFoldersWithItemCounts(IWorkItemCriteria criteria) { 
    var results = from folder in dataContext.Folders 
     select new { 
       Folder = folder, 
       Count = folder.WorkItems.Count() 
    }; 
    return(results); 
} 

Le problème est - je veux filtrer les éléments de travail qui sont comptés.

Cela fonctionne:

var results = from folder in dataContext.Folders 
     select new { 
       Folder = folder, 
       Count = folder.WorkItems.Where(item => item.ProjectId == criteria.ProjectId).Count() 
    }; 

mais je ne peux pas obtenir d'utiliser toute sorte de prédicat/expression dynamique. La syntaxe que je suis en train d'utiliser est:

var results = from folder in dataContext.Folders 
     select new { 
       Folder = folder, 
       Count = folder.WorkItems.Where(filter).Count() 
    }; 

J'ai essayé

Predicate<WorkItem> filter = (item => item.ProjectId == criteria.ProjectId); 

et

Expression<Func<WorkItem, bool>> filter = (item => item.ProjectId == criteria.ProjectId) 

ni qui compilera - donne The type arguments for method 'System.Linq.Enumerable.Where<TSource> (System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,bool>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Je j'ai essayé

Func<WorkItem, bool> filter = (item => item.ProjectId == criteria.ProjectId); 

qui génère, mais échoue avec 'surcharge non prise en charge utilisée pour l'opérateur de requête' Où '.'

Je vais avoir besoin d'ajouter des propriétés supplémentaires à l'interface IWorkItemCriteria, donc la possibilité de construire dynamiquement un prédicat qui peut être proprement traduit par Linq vers SQL est assez importante.

Des idées?

Répondre

1

Je pense que votre problème est que vous souhaitez référencer une expression (filtre) à partir d'une seconde expression (celle qui est passé à results.Where.Select()), et que le fournisseur LINQ to SQL IQueryable ne sait pas comment tirer la valeur de cela.

Ce que vous allez devoir faire est composer l'expression Select à partir de zéro afin de inline l'expression qui est votre filtre dynamique. Cela peut être très difficile avec des types anonymes, je ne suis pas sûr. Je viens de trouver l'article suivant, il semble bien expliquer cela: http://www.codeproject.com/KB/linq/rewrite_linq_expressions2.aspx

+0

http://twitter.com/dylanbeattie/status/3051746305773568 :) –

1

Quelque chose que j'attrapé hors de MSDN: l'idée est que vous pointez juste à une fonction existante:

using System;

public class GenericFunc

{ 
    public static void Main() 
    { 
     Func<string, string> convertMethod = UppercaseString; 
    } 

    private static string UppercaseString(string inputString) 
    { 
     return inputString.ToUpper(); 
    } 
} 

Je suis sûr qu'il ya aussi d'autres façons. Je me souviens de faire quelque chose comme

new Func<WorkItem, bool>((item => item.projectId == criteria.ProjectId)) 

Mais je ne suis pas sûr. plus, je suis tout à fait sûr que vous avez besoin de la "nouvelle", espérons que cela aide :)