Dans LINQ to SQL, comment passer des parties d’une requête LINQ dans une fonction

c# expression-trees linq linq-to-sql

Question

Est-il possible de passer des parties d'une requête linq dans une fonction? Je souhaite créer une interface commune pour mon DAL qui utilise toujours la même interface de requête. Par exemple,

List<T> Get(Join j, Where w, Select s){    
    return currentDataContext<T>.Join(j).Where(w).Select(s).ToList();    
}

Est-ce que ce genre de chose est possible? Je pense que ce serait fait avec des arbres d'expression, mais je n'ai pas pu en trouver d'exemples.

Réponse acceptée

Eh bien, la "jointure" est délicate, car il est très difficile d’exprimer une jointure - mais des choses comme où / select / orderby sont assez faciles ...

En réalité, il s’agit simplement de combiner les différentes méthodes LINQ sur IQueryable<T> , qui acceptent généralement Expression<Func<...>> pour certaines combinaisons. Donc, une sélection basique avec un prédicat optionnel serait:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

J'aurais tendance à retourner IQueryable<T> aussi, car c'est entièrement composable. Si l'appelant veut une liste, il peut toujours utiliser ToList() dessus ... ou (par exemple):

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

qui (en utilisant Northwind) fait la requête:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Le problème avec l'inclusion de la sélection (projection) dans la requête est que vous vous retrouveriez avec plusieurs types génériques. Étant donné que vous voulez souvent que la projection soit de type anonyme, il serait alors pratiquement impossible de spécifier le type de projection (anonyme) et le type de table, ce qui ne serait pas appelable.

En réalité, je me demande s’il est très utile d’écrire une telle méthode. Je pourrais juste coller avec une méthode de base:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Et laissez l'appelant le composer de la manière qu'il préfère - peut-être avec la syntaxe de requête:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Qui utilise:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Si vous souhaitez vraiment inclure l'ordre par projection et la projection, une méthode d'extension est l'approche la plus pratique. alors vous n'avez pas besoin de spécifier l'original (source) T (c'est ce qui le rend impossible à appeler lorsqu'il est mélangé avec anon-types):

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Ensuite, considérons une méthode DAL telle que:

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Qui utilise (encore, avec Northwind):

    public IQueryable<T> Get<T>(
        Expression<Func<T,bool>> predicate
        ) where T : class
    {
        IQueryable<T> query = (IQueryable<T>)GetTable(typeof(T));
        if (predicate != null) query = query.Where(predicate);
        return query;
    }

Réponse populaire

Vérifiez cette classe générique: TableView.cs .

Il utilise essentiellement un délégué Func <TEntity, bool> pour appliquer le prédicat Where:

//...
public TableView(DataContext dataContext, Expression<Func<TEntity, bool>> predicate)
{
    this.table = dataContext.GetTable<TEntity>();
    this.baseQuery = table.Where(predicate);
    this.predicate = predicate.Compile();
}
//...



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi