How to access properties of arguments when creating custom NHibernate HQL generator

I have the following custom type with a method on it to determine if one time span overlaps another

public struct DateTimeSpan
{
    public DateTime? Start { get; set; }
    public DateTime? End { get; set; }

    public bool Overlaps(DateTimeSpan overlap)
    {
        //....
    }
}

      

I am trying to write my own HQL generator, so when I use this method in my LINQ queries to access data, it will generate the appropriate SQL when I query the database.

This is the beginning of mine BaseHqlGeneratorForMethod

, which tries to compare the property of End

one DateTimeSpan

to another

public class DateSpanOverlapsDateTimeSpanHqlGenerator : BaseHqlGeneratorForMethod
{
    public DateSpanOverlapsDateTimeSpanHqlGenerator()
    {
        SupportedMethods = new[]
            {
                ReflectionHelper.GetMethodDefinition<DateTimeSpan>(x => x.Overlaps(new DateTimeSpan()))
            };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder builder, IHqlExpressionVisitor visitor)
    {
        var endTargetProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.End);
        Expression endTargetExpression = Expression.MakeMemberAccess(targetObject, endTargetProperty);

        var endArgumentProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.End);
        Expression endArgumentExpression = Expression.MakeMemberAccess(arguments[0], endArgumentProperty);

       return builder.GreaterThanOrEqual(visitor.Visit(endTargetExpression).AsExpression(), visitor.Visit(endArgumentExpression).AsExpression());
    }
}

      

I've proven that property End

in targetObject

is evaluating perfectly, but no matter what I do, I can't get it to evaluate property End

in arguments[0]

. The above code is just one example of what I have tried (and seems most obvious if it works for targetObject

), with most of the things I try to do with the exceptionAntlr.Runtime.NoViableAltException

The obvious difference between targetObject

and arguments[0]

is what targetObject

is of type PropertyExpression

and what arguments[0]

is of type ConstantExpression

. I'm guessing this means there must be different ways to access them, but I can't figure out what that is!

+3


source to share


2 answers


treeBuilder.Constant (arg.SubProperty); will cache your object so you have problems executing the request.

you have to add an overload to your DateTimeSpan

public bool Overlaps(DateTime? start, DateTime? end)

      

matches the signature in your DateSpanOverlapsDateTimeSpanHqlGenerator

SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition<DateTimeSpan>(span => span.Overlaps(default(DateTime?), default(DateTime?)))
};

      



and get the values ​​like this:

public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder builder, IHqlExpressionVisitor visitor)
{
    var startProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.Start);
    var endProperty = ReflectionHelper.GetProperty<DateTimeSpan, DateTime?>(x => x.End);

    MemberExpression targetStartExpression = Expression.MakeMemberAccess(targetObject, startProperty);
    MemberExpression targetEndExpression = Expression.MakeMemberAccess(targetObject, endProperty);

    HqlExpression startDateExpression = visitor.Visit(arguments[0]).AsExpression();
    HqlExpression endDateExpression = visitor.Visit(arguments[1]).AsExpression();
    ....
}

      

after that, as usual:

builder.LessThanOrEqual(visitor.Visit(targetStartExpression).AsExpression(), endDateExpression)

      

+2


source


I don't know if you resolved this or were still interested in the answer, however I stumbled upon this question myself while looking for a solution to this exact problem, so I thought I'd add my solution for others.

While debugging, I noticed that the target parameter is passed as a type expression PropertyExpression

, whereas my argument was passed as a type ConstantExpression

, so if it's great to add to PropertyExpression

, using Expression.Property

that doesn't work with a constant value.

Instead, I retrieve the constant value and access the sub-property values ​​directly, creating new constant expressions that I can then use to build the query expression.



I don't know if this is the best or most graceful way to do it, but it worked for me. Hope this helps.

 public class MyObject
 {
    public double SubProperty { get; set; }
 }

 private HqlTreeNode GenerateHQL(
    MethodInfo method,
    Expression targetObject,
    ReadOnlyCollection<Expression> arguments,
    HqlTreeBuilder treeBuilder,
    IHqlExpressionVisitor visitor)
{
    MyObject arg = (MyObject)((ConstantExpression)arguments[0]).Value;
    HqlConstant argExpression = treeBuilder.Constant(arg.SubProperty);

    ...
    ...
}

      

0


source







All Articles