问题
I want to extend the default LINQ provider for NHibernate 3 with methods of my own. I want to be able to use some methods from my POCOs. I have a component named Range which is used quite often in many of my POCOs. This nhibernate component class has a method Contains(int value) that I want to use in LINQ query expressions
Mapping:
<class name="Foo">
...
<component name="AgeRange">
<property name="Min" column="age_min" />
<property name="Max" column="age_max" />
</component>
</class>
Class
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;
I looked at several blog posts explaining how to extend the LINQ provider but I don't know how to build the expressions required for this to work.
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();
}
}
In the BuildHql method I don't know how to access Min and Max properties of my Range class to build a HqlTreeNode
回答1:
You can a manual approach: the easiest way is to create a LINQ tree that represents what you want:
arguments[0] >= targetObject.Min && arguments[1] <= targetObject.Max
. Here>=
isExpression.GreaterThenOrEqual
,.
isExpression.Property
and so on.When you have an expression tree, just apply
visitor
to it and return what it returns (I do not remember the exact API, but I can look into it if additional help is needed).Another solution may be to try my little library: Expressive.
It attempts to convert method IL into expressions, so you could do aLinqToHqlGeneratorsRegistry
orIRuntimeMethodHqlGenerator
that tries to inline any unknown property/method.
回答2:
There are a few good examples of extending the LINQ provider here: http://www.primordialcode.com/
来源:https://stackoverflow.com/questions/3916122/nhibernate-3-extending-linq-provider-basehqlgeneratorformethod-buildhql-proble