2014-01-24 41 views
2

我正在嘗試使用表達式創建動態nhibernate查詢。我對Contains,StartsWith和EndsWith這些函數沒有任何問題,但我似乎無法使它與IsNullOrEmpty一起使用。下面是一些背景:使用String.IsNullOrEmpty(string)和Nhibernate創建動態Linq表達式

包含:

MethodInfo contains = typeof(string).GetMethod("Contains", new Type[] { typeof(string) }); 
ParameterExpression param = Expression.Parameter(typeof(MyType), "x"); 
Expression expression = null; 
PropertyInfo info = typeof(MyType).Property("MyStringProperty"); 
expression = Expression.Property(param, info); 

expression = Expression.Call(expression, info, Expression.Constant("Does it contain this string", typeof(string))); 

在這一切結束時,表情是在調試器等於此:

expression = { x.MyStringProperty }; 

然後我把它變成一個lambda exrpression:

var finalExpression = Expression.Lambda<Func<MyType, bool>>(expression, param); 

在這最後,finalExpression是這樣的:

x => x.MyStringProperty.Contains("Does it contain this string"); 

當我通過nhibernate運行它時,它正是我想要的。隨着IsNullOrEmpty雖然,這是我所:

MethodInfo isNull = typeof(string).GetMethod("IsNullOrEmpty", new Type[] { typeof(string) }); 
ParameterExpression param = Expression.Parameter(typeof(MyType), "x"); 
PropertyInfo info = typeof(MyType).GetProperty("MyStringProperty"); 
expression = Expression.Property(param, info); 
expression = Expression.Call(isNull, expression); 

在這一切結束時,表達等於:

expression = { IsNullOrEmpty(x.MyStringProperty) } 

和之後的拉姆達轉換就變成:

finalExpression = { x => IsNullOrEmpty(x) } 

這看起來完全像它應該(雖然我承認也許它應該讀取string.IsNullOrEmpty(x)),但是當我通過nhibernate運行它時,出現錯誤:

NotSupportedException 
Message: Boolean IsNullOrEmpty(System.String) 

有誰知道這是爲什麼?如果我運行一個沒有動態查詢和手工編寫一個地方像這樣的條款,它的工作原理沒有問題:

nhibernateDataProvider.Where(x => string.IsNullOrEmpty(x.MySTringProperty)); 

任何人都知道這是爲什麼/如何解決這一問題?

編輯:

爲什麼我試圖做到這一點:

在我的web層我必須向用戶顯示這個x.MyStringProperty數據。他們有能力通過這個屬性進行過濾,我希望能夠通過這些字符串方法來過濾數據。網絡層簡單地將這些功能向後:

BeginsWith 
EndsWith 
Contains 
IsNullOrEmpty 
NotIsNullOrEmpty 

從這些名稱我可以直接把它們變成使用上述代碼串的方法。正因爲如此,我可以傳遞我的web圖層中的任何類型,並且能夠過濾任何字符串屬性。這非常強大,因爲對於我所有的數百個類,我可以有一個方法來處理每個類的過濾。正如我之前所說的,它可以用在非靜態的方法,因爲內置的表達式爲:

x -> x.MyStringProperty.NonStaticMethod("SomeFilterValue"); 

是說,對Expression.Call文檔權,你應該能夠用靜態方法來做到這一點。由於它適用於非靜態方法,必須有一種方法做IsNullOrEmpty使得表達變得

x -> string.StaticMethod(x.MyStringProperty) 

我敢打賭你,如果我創建表達

x -> x.MySTringProperty == null || x.MySTringProperty == "" 

它會工作,但也就是一個工作,作爲一名程序員,我覺得出於原則,我需要找出如何使用靜態方法來完成上述操作。

回答

3

我只是不確定你想在這裏實現什麼。 動態表達式查詢語言已經存在:它是內置的LINQ提供程序。但是,讓我們試着給你更多關於它的實現的信息。

當內置的Linq提供程序接收到由表達式樹表示的查詢時,使用訪問者模式將其轉換爲SQL(具有中間HQL步驟)。一個強大的部分是通過接口IHqlGeneratorForMethod

public interface IHqlGeneratorForMethod 
{ 
    IEnumerable<MethodInfo> SupportedMethods { get; } 
    HqlTreeNode BuildHql(MethodInfo method, Expression targetObject 
      , ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder 
      , IHqlExpressionVisitor visitor); 
} 

這裏的重要組成部分,所表示的方法檢查一組實現者:

DictionaryItemGenerator 
DictionaryContainsKeyGenerator 
EqualsGenerator 
BoolEqualsGenerator 
MathGenerator 
AnyHqlGenerator 
AllHqlGenerator 
MinHqlGenerator 
MaxHqlGenerator 
CollectionContainsGenerator 
HqlGeneratorForExtensionMethod 
StartsWithGenerator // StartsWith 
EndsWithGenerator // EndsWith 
ContainsGenerator // Contains 
ToLowerGenerator 
ToUpperGenerator 
SubStringGenerator 
IndexOfGenerator 
ReplaceGenerator 
TrimGenerator 

正如你所看到的,也有ContainsEndsWithStartsWith的responsibles 。但IsNullOrEmpty不能在那裏找到。

換句話說,無論你在全球正在做的事情,你應該IsNullOrEmpty在這樣的聲明結束了:

.Where(x => x.MyProperty == null || x.MyProperty == "") 
+0

我非常感謝您的回覆。我編輯了上述內容,爲您提供更多信息。上面的解決方案可能會工作,我很快就會檢查出來,但也許您在編輯中也有問題的答案。 – Magn3s1um

+0

我其實使用非常相似的邏輯。我的意思是,綁定服務器上的Filter對象,然後將其轉換爲Restrictions(Criteria API)。我會說,它可以以類似的方式用於你的情況。怎麼運行的?不是構建表達式,而是通過幾個擴展方法傳遞Criteria。如果它們中的任何一個能夠正確讀取過濾器,則附加限制。限制對字符串有很強的支持,所以如果我在過濾器綁定上應用足夠的驗證,我可以使用字符串。也許這可能會有所幫助,但它不是靜態方法的表達式生成器的答案;) –

+1

我們從標準切換到Linq到nhibernate,所以表達式是必需的。我會看看== null || 「」解決方案有效。我會回覆結果,如果有效,我會給你答案。再次感謝 – Magn3s1um