4 votes

NHibernate 3 - problème d'extension du fournisseur Linq BaseHqlGeneratorForMethod.BuildHql

Je veux étendre le fournisseur LINQ par défaut de NHibernate 3 avec mes propres méthodes. Je veux pouvoir utiliser certaines méthodes de mes POCOs. J'ai un composant nommé Range qui est utilisé assez souvent dans plusieurs de mes POCOs. Cette classe de composant nhibernate possède une méthode Contains(int value) que je veux utiliser dans les expressions de requêtes LINQ.

Cartographie :

<class name="Foo">
  ...
  <component name="AgeRange">
    <property name="Min" column="age_min" />
    <property name="Max" column="age_max" />
  </component>
</class>

Classe

public class Range {
  public int Min { get; set; }
  public int Max { get; set; }

  public bool Contains(int value) {
    return value >= this.Min && value <= this.Max;
  }
}

// this is the LINQ query I want to be able to write
// which will generate 'SELECT * FROM Foo WHERE 25 BETWEEN age_min AND age_max'
var s = from x in session.Query<Foo> where x.AgeRange.Contains(25) select x;

// I know the following works
var s = from x in session.Query<Foo> where x.AgeRange.Min <= 25 && x.AgeRange.Max >= 25 select x;

J'ai consulté plusieurs articles de blog expliquant comment étendre le fournisseur LINQ, mais je ne sais pas comment construire les expressions nécessaires pour que cela fonctionne.

public class RangeContainsGenerator : BaseHqlGeneratorForMethod
{
    public MemberInfo RangeMin;
    public MemberInfo RangeMax;

    public RangeContainsGenerator() {
        SupportedMethods = new[] { 
            ReflectionHelper.GetMethodDefinition<Range>(x=> x.Contains(0)),
        };

        RangeMin = ReflectionHelper.GetProperty<Range, int>(x => x.Min);
        RangeMax = ReflectionHelper.GetProperty<Range, int>(x => x.Max);
    }

    public override NHibernate.Hql.Ast.HqlTreeNode BuildHql(
        System.Reflection.MethodInfo method, 
        System.Linq.Expressions.Expression targetObject, 
        System.Collections.ObjectModel.ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, 
        NHibernate.Hql.Ast.HqlTreeBuilder treeBuilder, 
        NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor) {
            // The targetObject parameter contains the "Foo.AgeRange" member access expression
            throw new NotImplementedException(); 
    }
}

Dans la méthode BuildHql, je ne sais pas comment accéder aux propriétés Min et Max de ma classe Range pour construire un HqlTreeNode.

2voto

Andrey Shchekin Points 7740
  1. Vous pouvez adopter une approche manuelle : le moyen le plus simple est de créer un arbre LINQ qui représente ce que vous voulez : arguments[0] >= targetObject.Min && arguments[1] <= targetObject.Max . Ici >= es Expression.GreaterThenOrEqual , . es Expression.Property et ainsi de suite.

    Lorsque vous avez un arbre d'expression, il suffit d'appliquer visitor et retourner ce qu'il retourne (je ne me souviens pas de l'API exacte, mais je peux y jeter un coup d'œil si vous avez besoin d'aide supplémentaire).

  2. Une autre solution peut être d'essayer ma petite bibliothèque : Expressif .
    Il tente de convertir les méthodes IL en expressions, de sorte que vous pourriez faire un LinqToHqlGeneratorsRegistry o IRuntimeMethodHqlGenerator qui essaie de mettre en ligne tout propriété/méthode inconnue.

1voto

Diego Mijelshon Points 40314

Il existe quelques bons exemples d'extension du fournisseur LINQ ici : http://www.primordialcode.com/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X