Pour pouvoir interroger sur les propriétés calculées, vous disposez d'au moins 2 options:
1) vous amassez les valeurs calculées valeurs dans la base de données avec les lignes (ou dans une table différente), et les utiliser dans vos requêtes bien sûr cela nécessite le changement de modèle de données, et la redondance dans les données, mais est le moyen le plus performant. 2) vous devez être capable d'exprimer la façon dont vous "calculez" les propriétés d'une manière que sql comprendra, ce qui signifie que la propriété doit être remplacée par un linq. expression dans la requête finale. J'ai trouvé en 2009 un article incroyable d'Eric Lippert sur l'enregistrement de ces propriétés, mais je ne le trouve plus. En tant que tel ici est un link à un autre, qui a la même idée. Fondamentalement, vous définissez votre calcul comme un arbre d'expression, et utilisez la version compilée dans votre code.
Pour le rendre plus pratique, vous attribuer votre propriété avec un
[AttributeUsage(AttributeTargets.Property)]
class CalculatedByAttribute: Attribute
{
public string StaticMethodName {get; private set;}
public CalculatedByAttribute(string staticMethodName)
{
StaticMethodName = staticMethodName;
}
}
Comme:
public partial class Something
{
[CalculatedBy("calculatedExpression")]
public int calculated { get { return calculatedExpression.Compile()(this); } }
public static Expression<Func<Something, int>> calculatedExpression = s => s.a * s.b;
}
(bien sûr vous pouvez mettre en cache la compilation) :)
Puis, en votre méthode, si la propriété a votre attribut, vous obtenez la valeur de la propriété statique et l'utilisez dans vos requêtes. Quelque chose le long:
public static object ExecuteLinqMethod<T>(IQueryable<T> q, string Field, string Method)
{
var propInfo = typeof(T).GetProperty(Field);
LambdaExpression exp;
var myAttr = propInfo.GetCustomAttributes(typeof(CalculatedByAttribute), true).OfType<CalculatedByAttribute>().FirstOrDefault();
if (myAttr != null)
exp = (LambdaExpression)typeof(T).GetField(myAttr.StaticMethodName, BindingFlags.Static | BindingFlags.Public).GetValue(null);
else
{
var param = Expression.Parameter(typeof(T), "p");
Expression prop = Expression.Property(param, Field);
exp = Expression.Lambda(prop, param);
}
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp);
return q.Provider.Execute(mce);
}
Pourquoi pensez-vous que l'arbre d'expression peut vous permettre de faire quelque chose qui n'est pas supporté par le fournisseur de requêtes EF? –
J'ai besoin de la méthode universelle pour trouver max, min, sum etc. des propriétés mappées et non mappées. Avec le nom donné de la fonction et le nom de la propriété en tant que paramètres de cette méthode. Cela peut être fait par l'arbre d'expression ou d'une autre manière. –
Alors pourquoi ne trouvez-vous pas "l'autre chemin" d'abord, puis demandez l'aide de l'arbre d'expression si nécessaire. Je suppose que le principal problème est de savoir comment déterminer si le champ est mappé ou non. Et même si vous faites cela, puisqu'il n'y a aucun moyen de savoir ce que la propriété calculée utilise, la seule façon de l'exécuter sera de l'exécuter par rapport à 'IEnumerable'. –