2013-02-19 42 views
3

當訪問參數的屬性我有它的方法下面的自定義類型,以確定一個時間跨度重疊的另一如何編寫自定義的NHibernate HQL發電機

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

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

我試圖寫一個自定義HQL發生器所以當我在我的數據訪問LINQ查詢中使用這個方法時,它將在查詢數據庫時生成適當的SQL。

這是我BaseHqlGeneratorForMethod的試圖的一個DateTimeSpanEnd屬性與其他

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

我已經證明,在targetObjectEnd屬性被評價不錯,但不管比較開始了我我是否無法通過arguments[0]來評估End財產。上面的代碼只是其中的一個我曾嘗試例子(似乎是最明顯的給出它的工作原理爲targetObject)與大多數的事情,我嘗試用異常targetObjectarguments[0]之間​​

一個明顯的不同碰得是targetObjectPropertyExpressionarguments[0]類型是ConstantExpression。我認爲這意味着需要有不同的方法來訪問它們,但我無法弄清它是什麼!

回答

0

我不知道你是否曾經解決過這個問題,或者仍然對答案感興趣,但是我自己偶然發現了這個問題,同時尋找解決這個確切問題的方法,所以認爲我會爲其他人添加解決方案。

在調試,我注意到,目標對象參數傳遞作爲PropertyExpression類型的表達式,而我的參數傳遞中作爲一種類型的ConstantExpression,因此,雖然它是完全有效利用Expression.Property添加到PropertyExpression,那並不是」 t以不變的價值工作。

而是我提取常量的值並直接訪問子屬性的值,創建新的常量表達式,然後我可以使用它來構建查詢表達式。

我不知道這是否是最好的,或最優雅的方式來做到這一點,但它對我有效。我希望它有幫助。

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

    ... 
    ... 
} 
2

treeBuilder.Constant(arg.SubProperty);會緩存你的對象,所以當你運行你的查詢時,你最終會遇到問題。之後,企業

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

你應該以這種方式添加的過載到您的DateTimeSpan

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

匹配簽名到您的DateSpanOverlapsDateTimeSpanHqlGenerator

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

,並獲得價值照常:

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