2013-05-01 53 views
4

我正在嘗試使用與Query<T>()QueryOver<T>()內使用計算的屬性。當使用LINQ查詢時,我可以使用自定義的DefaultLinqToHqlGeneratorsRegistry註冊自定義生成器。這適用於calculated properties from an expression,因此代碼不會重複。QueryOver是否有查詢生成器或擴展點,就像LINQ一樣?

我似乎無法找到爲QueryOver API註冊自定義生成器的擴展點。它存在嗎?

我想不是必須複製原始SQL字符串(Map(x => x.Prop).Formula("query").LazyLoad().Access.ReadOnly())內部的計算屬性邏輯。這意味着兩倍的邏輯和兩倍的測試。

根據我所看到的source,QueryOver API使用Criterion作爲其基礎...直接轉換爲原始SQL而不是HQL。

回答

3

LINQ和QueryOver採取不同的路徑到SQL:

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

的標準有NHibernate.Impl.ExpressionProcessor.RegisterCustomMethodCall(...);這可能是你想要的。

一個簡單的例子:

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)); 
    } 
} 

不要忘記調用註冊()。之後,你可以使用它像這樣:

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

是的我發現這只是在通過源代碼查看時的另一個晚上。最大的問題是它需要一個單獨的'Expression'到'ICriteria'處理器。我會看到我想出的,然後讓你知道。 – TheCloudlessSky 2013-05-06 11:34:06

0

一個簡單的例子:

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)); 
    } 
} 

不要忘記調用註冊()。之後,你可以這樣使用它:

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

你介意把這個與upvoted的答案合併嗎?我只是自己做一個例子,但你已經做到了:)。 – TheCloudlessSky 2013-05-15 16:55:56

+0

當然。你可以做到嗎? – 2013-05-16 16:34:51

+0

當然可以。完成。 – TheCloudlessSky 2013-05-16 22:57:43