2010-08-09 27 views
7

在我的代碼中的第(3)處,我定義了一個名爲query1的查詢,其中我定義了一個.Where lambda表達式。此查詢在某種程度上是動態的,但仍包含靜態元素,它始終引用類型員工及其(int)屬性ClientID。用表達式樹創建完全動態的where子句並在IQueryable上執行

現在我非常喜歡根據方法參數來指出類型及其屬性的動態,這些參數的示例如下面的點(1)所示。

我到目前爲止所做的嘗試是通過用(4),(5)&(6)中寫下的更精細的表達式樹替換它,使點(3)下定義的查詢的靜態部分完全動態化。 。但是,當我嘗試將所有內容添加到一起時,它說我打電話。帶有錯誤參數的地方。我不知道如何調用。用正確的參數爲了創建一個完全動態的選擇。

有人知道解決這個問題嗎?我花了一天的搜索時間,到目前爲止還沒有找到解決方案。

 dsMain domainService = new dsMain(); 


     //(1)i want to rewrite the following four variables to method-parameters 
     Type entityType = typeof(Employee); 
     String targetProperty = "ClientID"; 
     Type entityProperty = typeof(Employee).GetProperty(targetProperty).PropertyType; 
     int idToDelete = 5; 


     //(2)create expression-function: idToDelete == entityType.targetProperty (in this case: Employee.ClientID) 
     ParameterExpression numParam = Expression.Parameter(entityProperty, targetProperty.Substring(0, 3)); 
     ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType()); 
     BinaryExpression intEqualsID = Expression.Equal(numParam, equalTarget); 
     Expression<Func<int, bool>> lambda1 = 
        Expression.Lambda<Func<int, bool>>(
        intEqualsID, 
        new ParameterExpression[] { numParam }); 

     //(3)I want to create query1 fully dynamic, so defining Employee or an other type and its property at run time 
     WhereClause = lambda1.Compile(); 
     IQueryable<Employee> employees = domainService.GetEmployees(); 
     var query1 = employees.Where<Employee>(C => WhereClause.Invoke(C.ClientID)).Expression; 



     //(4)create the operand body {value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)} 
     var operandbodyMethod = WhereClause.GetType().GetMethod("Invoke"); 
     var operandbodyType = typeof(System.Boolean); 
     var operandbodyArgs1Expression = Expression.Parameter(entityType, entityType.Name.Substring(0, 1)); 
     var operandbodyArgs1 = Expression.MakeMemberAccess(operandbodyArgs1Expression, entityType.GetMember(targetProperty)[0]); 
     var operandBodyObjectExp = Expression.Constant(this, this.GetType()); 
     var operandbodyObject = Expression.MakeMemberAccess(operandBodyObjectExp, this.GetType().GetMember("WhereClause")[0]); 

     //(5)create the operand {E => value(ASP.test_aspx).WhereClause.Invoke(E.ClientID)} 
     var operandbody = Expression.Call(operandbodyObject, operandbodyMethod, operandbodyArgs1); 
     var operandParameter = Expression.Parameter(entityType, entityType.Name.Substring(0, 1)); 
     var operandType = typeof(Func<,>).MakeGenericType(entityType, typeof(System.Boolean)); 

     //(6) 
     var operand = Expression.Lambda(operandType, operandbody, new ParameterExpression[] { operandParameter }); 
     var expressionType = typeof(Expression<>).MakeGenericType(operandType); 
     var completeWhereExpression = Expression.MakeUnary(ExpressionType.Quote, operand, expressionType); 


     //(7)the line below does not work 
     var query2 = employees.Where<Employee>(completeWhereExpression).Expression; 

非常感謝您閱讀我的問題! 如果您有關於我的問題的問題,請讓他們:)

+0

不管你用表達式樹創造什麼,你仍然需要有一個IQueryable來操作。在你的例子中,什麼是domainService?看起來像某種數據上下文,但不是LinqToSql的。你有一個方法,GetEmployees()就可以了,domainService是否提供了任何基於System.Type獲取IQueryable的機制,比如LinqToSql的呢? – 2010-08-09 22:30:54

+0

domainService擴展了LinqToEntitiesDomainService (http://bit.ly/dr8Zkd),它是WCF RIA Services框架(http://bit.ly/aHusJT)的一部分。 domainService對於我的EDM中稱爲dbUbiHorecaEntities的每個實體都有特定的CRUD方法。它沒有特殊的機制來獲得基於System.Type的IQueryables,但是,它可能帶有反射:每個實體X在domainService中都有一個名爲getX()的get方法,返回一個IQueryable 。示例:IQueryable = domainService.GetType()。GetMethod(「Get」+ X.getType()。GetName())。Invoke(domainService,null)。這對你有幫助嗎? – 2010-08-09 22:57:55

回答

19

這是挺難看的隔離,但所發生的第一件事情就是Compile看起來不合適的IQueryable - 將很少工作(LINQ到對象是例外)。

有相當於WhereClause.Invoke(C.ClientID)是使用Expression.Invoke調用子表達式,但即使是這樣古怪:LINQ到SQL會支持它,EF(3.5至少)沒有(也許「沒「;我沒有重新檢查4.0)。最終,這將是更強大的創建lambda1Expression<Func<Employee,bool>>如果可能的話:

ParameterExpression empParam = Expression.Parameter(typeof(Employee),"emp"); 
    ConstantExpression equalTarget = Expression.Constant(idToDelete, idToDelete.GetType()); 
    BinaryExpression intEqualsID = Expression.Equal(
     Expression.PropertyOrField(empParam, targetProperty), equalTarget); 
    Expression<Func<Exmployee, bool>> lambda1 = 
       Expression.Lambda<Func<int, bool>>(
       intEqualsID, 
       empParam); 

然後通過Where

var query1 = employees.Where(lambda1); 
+1

謝謝Marc!有效!而這麼小的代碼。 (順便說一句,這是可能的在EF 4.0 :))(也感謝你柯克爲你的努力:)) – 2010-08-10 08:15:58

+0

簡單明白!謝謝 – 2016-03-08 14:32:27