TheCloudlessSky
TheCloudlessSky

Reputation: 18363

Is there a query generator or extension point for QueryOver like there is for LINQ?

I'm trying to use calculated properties that I use with Query<T>() inside of a QueryOver<T>(). When using a LINQ query, I can register custom generators with a custom DefaultLinqToHqlGeneratorsRegistry. This works great for calculated properties from an expression so the code isn't duplicated.

I can't seem to find the extension point for registering custom generators for the QueryOver API. Does it exist?

I'd like to not have to duplicate the calculated property logic inside of a raw SQL string (Map(x => x.Prop).Formula("query").LazyLoad().Access.ReadOnly()). This would means twice the logic and twice the number of tests.

From what I've seen through the source, the QueryOver API uses Criterion as its base... which directly translates to raw SQL rather than HQL.

Upvotes: 4

Views: 527

Answers (2)

Firo
Firo

Reputation: 30813

Linq and QueryOver take different paths to sql:

QueryOver -> Expression -> Criteria \
Linq      -> LinqParser -> Hql      --> Sql

for Criteria there is NHibernate.Impl.ExpressionProcessor.RegisterCustomMethodCall(...); which might be what you want.

A simple example:

public static class QueryOverExtensions
{
    public static void Register()
    {
        ExpressionProcessor.RegisterCustomProjection(() => QueryOverExtensions.Day(default(DateTime)), QueryOverExtensions.ProcessDay);
        ExpressionProcessor.RegisterCustomProjection(() => QueryOverExtensions.Month(default(DateTime)), QueryOverExtensions.ProcessMonth);
        ExpressionProcessor.RegisterCustomProjection(() => QueryOverExtensions.Year(default(DateTime)), QueryOverExtensions.ProcessYear);
    }

    public static Int32 Day(this DateTime dateTimeProperty)
    {
        return (dateTimeProperty.Day);
    }

    public static Int32 Month(this DateTime dateTimeProperty)
    {
        return (dateTimeProperty.Month);
    }

    public static Int32 Year(this DateTime dateTimeProperty)
    {
        return (dateTimeProperty.Year);
    }

    private static IProjection ProcessDay(MethodCallExpression methodCallExpression)
    {
        IProjection property = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]).AsProjection();
        return (Projections.SqlFunction("day", NHibernateUtil.Int32, property));
    }

    private static IProjection ProcessMonth(MethodCallExpression methodCallExpression)
    {
        IProjection property = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]).AsProjection();
        return (Projections.SqlFunction("month", NHibernateUtil.Int32, property));
    }

    private static IProjection ProcessYear(MethodCallExpression methodCallExpression)
    {
        IProjection property = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]).AsProjection();
        return (Projections.SqlFunction("year", NHibernateUtil.Int32, property));
    }
}

Don't forget to call Register(). After that you can use it like this:

session.QueryOver<Order>().Where(o => o.Date.Month() == DateTime.Today.Month).List();

Upvotes: 3

Ricardo Peres
Ricardo Peres

Reputation: 14555

A simple example:

public static class QueryOverExtensions
{
    public static void Register()
    {
        ExpressionProcessor.RegisterCustomProjection(() => QueryOverExtensions.Day(default(DateTime)), QueryOverExtensions.ProcessDay);
        ExpressionProcessor.RegisterCustomProjection(() => QueryOverExtensions.Month(default(DateTime)), QueryOverExtensions.ProcessMonth);
        ExpressionProcessor.RegisterCustomProjection(() => QueryOverExtensions.Year(default(DateTime)), QueryOverExtensions.ProcessYear);
    }

    public static Int32 Day(this DateTime dateTimeProperty)
    {
        return (dateTimeProperty.Day);
    }

    public static Int32 Month(this DateTime dateTimeProperty)
    {
        return (dateTimeProperty.Month);
    }

    public static Int32 Year(this DateTime dateTimeProperty)
    {
        return (dateTimeProperty.Year);
    }

    private static IProjection ProcessDay(MethodCallExpression methodCallExpression)
    {
        IProjection property = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]).AsProjection();
        return (Projections.SqlFunction("day", NHibernateUtil.Int32, property));
    }

    private static IProjection ProcessMonth(MethodCallExpression methodCallExpression)
    {
        IProjection property = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]).AsProjection();
        return (Projections.SqlFunction("month", NHibernateUtil.Int32, property));
    }

    private static IProjection ProcessYear(MethodCallExpression methodCallExpression)
    {
        IProjection property = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]).AsProjection();
        return (Projections.SqlFunction("year", NHibernateUtil.Int32, property));
    }
}

Don't forget to call Register(). After that you can use it like this:

session.QueryOver<Order>().Where(o => o.Date.Month() == DateTime.Today.Month).List();

Upvotes: 0

Related Questions