2017-04-10 2 views
1

J'utilise une version modifiée de LinqKit afin d'avoir mes extensions en un seul endroit.Expression statique en tant que propriété d'instance pour les requêtes linq dynamiques

Par conséquent, j'ai une seule partie de chacune de mes classes d'entités où je définis mon expression, par ex. pour tblMain:

public partial class tblMain 
{ 
    public static Expression<Func<tblMain, bool>> IsVisible => (e) => e.MainStatus == "Visible"; 
} 

Dans une requête, je suis maintenant capable d'écrire quelque chose comme ça

var visibleEntries = dbContext 
    .tblMain 
    .AsExpandable() 
    .Where(m => tblMain.IsVisible.Invoke(m)) 
    .ToList(); 

qui me retourner toutes les entrées visibles de la table tblMain.

Je me demandais s'il y avait un moyen de ne pas avoir cette propriété statique. Cela me permettrait d'utiliser Interfaces comme IVisibilityEntity pour forcer une propriété publique IsVisible sur des types spécifiques.

Pour l'instant j'ai fini avec:

public Expression<Func<bool>> IsVisible2 => Expression.Lambda<Func<bool>>(Expression.Invoke(IsVisible, Expression.Variable(typeof(tblMain)))); 

mais cela me jette une exception

InvalidOperationException: variable 'm' de type 'tblMain' référencé du champ d'application '', mais ce n'est pas défini.

Même chose lors de l'utilisation de Expression.Constant(this, typeof(tblMain)) comme deuxième paramètre.

Ce que j'aimerais avoir est une requête comme

var visibleEntries = dbContext 
    .tblMain 
    .AsExpandable() 
    .Where(m => m.IsVisible.Invoke()) 
    .ToList(); 

Cela peut sembler pas beaucoup d'un changement. Mais je veux vraiment pouvoir utiliser la fonction d'interface pour décrire mon modèle de base de données sous-jacent.

Avec des interfaces, il permet également des vérifications, par ex. if(myEntity is IVisibilityEntity) pour effectuer des tâches de visibilité spécifiques.

Des idées si cela est possible et comment cela peut-il être réalisé?

Édition 1

Dès le premier commentaire. J'utilise LinqKit pour permettre la même logique pour les sous-requêtes:

var visibleEntries = dbContext 
    .tblMain 
    .AsExpandable() 
    .Where(m => tblMain.IsVisible.Invoke(m)) 
    .Select(m => new 
    { 
     VisibleSubs = m.tblSub.Where(s => tblSub.IsVisible.Invoke(s)).Select(s => new 
     { 
      // ... 
     }) 
    }) 
    .ToList(); 

La requête serait au-dessus de me donner tous les principaux-entrées visibles et leurs associés (et visibles) sous-entrées. Mais ce n'est pas possible d'écrire simplement m.tblSub.Where(tblSub.IsVisible) car cela montre

CS1929 'ICollection<tblSub>' does not contain a definition for 'Where' and the best extension method overload 'Queryable.Where<tblSub>(IQueryable<tblSub>, Expression<Func<tblSub, bool>>)' requires a receiver of type 'IQueryable<tblSub>' 
+0

Dans votre premier extrait, vous pouvez écrire '.Where (tblMain.IsVisible)' et vous n'avez même plus besoin de LINQKit. – Servy

+0

@Servy Je connais cet usage.S'il vous plaît voir ma question mise à jour ('Edit 1'). De plus, cette solution ne résoudra pas le problème d'interface et ne convient pas aux sous-requêtes. – KingKerosin

Répondre

0

ce que sur la définition de vos propriétés comme ceci: https://damieng.com/blog/2009/06/24/client-side-properties-and-any-remote-linq-provider Il est essentiellement la définition de la propriété sous forme de:

partial class Employee { 
    private static readonly CompiledExpression<Employee,string> fullNameExpression 
    = DefaultTranslationOf<Employee>.Property(e => e.FullName).Is(e => e.Forename + " " + e.Surname); 
    private static readonly CompiledExpression<Employee,int> ageExpression 
    = DefaultTranslationOf<Employee>.Property(e => e.Age).Is(e => DateTime.Now.Year - e.BirthDate.Value.Year - (((DateTime.Now.Month < e.BirthDate.Value.Month) || (DateTime.Now.Month == e.BirthDate.Value.Month && DateTime.Now.Day < e.BirthDate.Value.Day)) ? 1 : 0))); 

    public string FullName { 
    get { return fullNameExpression.Evaluate(this); } 
    } 

    public int Age { 
    get { return ageExpression.Evaluate(this); } 
    } 
} 

et l'utilisation du Package Microsoft.Linq.Translations à résoudre.