2010-08-09 26 views
7

Tại thời điểm (3) trong mã của tôi, tôi đã định nghĩa một truy vấn được gọi là query1, trong đó tôi đã định nghĩa một biểu thức lambda. Truy vấn này theo một cách nào đó động nhưng vẫn chứa các phần tử tĩnh, nó luôn đề cập đến Type Employee và thuộc tính ClientID (int) của nó.Tạo mệnh đề where đầy đủ năng động với cây biểu thức và thực hiện trên IQueryable

Bây giờ tôi rất muốn làm cho tham chiếu đến loại và tính chất động của nó, dựa trên các tham số phương thức, ví dụ được hiển thị bên dưới điểm (1).

Những gì tôi đã cố gắng làm cho phần tĩnh của truy vấn được xác định theo điểm (3) hoàn toàn năng động bằng cách thay thế nó bằng một cây biểu thức phức tạp hơn như được viết trong (4), (5) & (6) . Nhưng khi tôi cố gắng thêm tất cả mọi thứ với nhau nó nói tôi gọi. Có thông số sai. Tôi không biết cách gọi. Có các thông số phù hợp để tạo ra một lựa chọn đầy đủ năng động.

Có ai đó biết để giải quyết vấn đề này không? Tôi đã dành một ngày tìm kiếm và không tìm thấy giải pháp cho đến nay.

 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; 

Cảm ơn bạn rất nhiều vì đã đọc câu hỏi của tôi! Nếu bạn có thắc mắc về câu hỏi của tôi, xin vui lòng yêu cầu họ :)

+0

Không có vấn đề gì bạn tạo ra với cây biểu thức, bạn vẫn sẽ cần để có một IQueryable để hoạt động. Trong ví dụ của bạn, domainService là gì? Hình như một số loại bối cảnh dữ liệu, nhưng không phải của LinqToSql. Bạn có một phương thức, GetEmployees() trên nó, không domainService cung cấp bất kỳ cơ chế nào để có được IQueryable dựa trên một System.Type, giống như của LinqToSql không? –

+0

domainService mở rộng LinqToEntitiesDomainService (http://bit.ly/dr8Zkd), nó là một phần của khung dịch vụ WCF RIA (http://bit.ly/aHusJT). domainService có các phương thức CRUD cụ thể cho từng thực thể trong EDM của tôi được gọi là dbUbiHorecaEntities. Nó không có cơ chế đặc biệt để có được IQueryables dựa trên System.Type, tuy nhiên, nó có thể với sự phản chiếu: mỗi thực thể X có một phương thức get trong domainService gọi là getX(), trả về một IQueryable . Ví dụ: IQueryable = domainService.GetType() GetMethod ("Get" + X.getType(). GetName()). Invoke (domainService, null). Đây có phải là trợ giúp cho bạn không? –

Trả lời

19

này là khá khó để nhìn vào trong sự cô lập, nhưng điều đầu tiên xảy ra là Compile trông lạc lõng cho IQueryable - đó sẽ hiếm khi công việc (LINQ-to-Objects là ngoại lệ).

Tương đương với WhereClause.Invoke(C.ClientID) là sử dụng Expression.Invoke để gọi biểu thức con, nhưng ngay cả điều này là flakey: LINQ-to-SQL sẽ hỗ trợ nó, EF (trong 3,5 ít nhất) không (có thể "không "; Tôi chưa kiểm tra lại trong 4.0). Cuối cùng, nó sẽ mạnh mẽ hơn để tạo lambda1 như một Expression<Func<Employee,bool>> nếu có thể:

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

Sau đó vượt qua này-Where:

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

Cảm ơn bạn Marc! Nó đã làm việc! Và quá ít mã. (Btw, nó có thể trong EF 4.0 :)) (cũng cảm ơn bạn Kirk cho bạn nỗ lực :)) –

+0

Đơn giản để hiểu! cảm ơn –

Các vấn đề liên quan