簡體   English   中英

如何動態構建表達式樹以用於匿名類型

[英]How do I dynamically construct an Expression Tree to use with anonymous types

這是我在這里的第一篇文章。 如果我違反了任何准則,請告訴我,我很樂意糾正它們。

我有以下實體類:

public class Book
{
public int BookID { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
}

還有第二個實體類,

public class Library
{
public int ID  { get; set; } 
public Book Book { get; set; }
public int Count { get; set; }
}

我也有這個函數可以根據用戶輸入動態生成一個 lambda 表達式。

public static Expression<Func<T, bool>> GetLambdaExpression<T>(List<Operation> OperationList)
        {  
            ExpressionTree expressionTree = new ExpressionTree();
            Node Root = expressionTree.ConstructTree(OperationList);

            var Parameter = Expression.Parameter(typeof(T), "x");
            var Expression = CalculateExpression(Root);  //Returns an Expression Clause by And/Or every input in OperationList
            return Expression.Lambda<Func<T, bool>>(Expression, Parameter); //Finally creating Lambda
        }


操作類包含有關操作類型、字段和值的詳細信息。 它從客戶端傳遞,我通過映射字段​​名稱對實體類使用查詢。

以這種方式使用時,代碼按預期工作,

var OperationList = //Get from client
var LambdaExpression = GetLambdaExpression<Book>(OperationList);
var result = _BookContext.Books.Where(LambdaExpression);

或者

var OperationList = //Get from client
var LambdaExpression = GetLambdaExpression<Library>(OperationList);
var result = _LibraryContext.Library.Where(LambdaExpression);

我正在嘗試使用 LINQ 加入兩個實體類,但我似乎無法找到一種方法來為由 JOIN 返回的生成的匿名類型動態創建 Lambda 表達式。

我的加入看起來像,

 var result = from c in _BookContext.Books

              join d in _LibraryContext.Library

              on c.BookID equals d.ID

              select new { c , d };

但是,由於明顯的原因,這不起作用,

var OperationList = //Passed from client
var LambdaExpression = GetLambdaExpression<T>(OperationList);
result.Where(LambdaExpression); 

將“對象”或“動態”傳遞給 GetLambdaExpression() 不起作用,因為字段名稱不是預定義的,並且會引發異常。

如何為匿名類型構建表達式樹。

非常感謝。

更新

我設法解決了它。 這是我所做的:

我沒有將聯接的結果存儲到匿名類型中,而是創建了一個新類,該類具有用於執行聯接的實體類的對象。

public class JoinResult
    {
        public Book Book { get; set; }
        public Library Library { get; set; }
    }

執行連接並將數據存儲到 JoinResult

var result = from c in _BookContext.Books

              join d in _LibraryContext.Library

              on c.BookID equals d.ID

              select new JoinResult{ Book = c , Library = d };

最后,這是為 JoinResult 動態創建 Lambda 表達式的技巧。

我為 JoinResult 創建了一個表達式參數,然后為 JoinResult 的屬性創建了表達式屬性。

我使用創建的表達式屬性作為參數傳遞給實體類的新屬性。 本質上,以“x.Book.BookID”格式創建屬性。

例如,如果我想對 JoinResult 執行 EqualOperation。 這是我將如何做到的。

public static IQueryable<T> PerformEqualOperation<T>(int Constant, int FieldName, Type Prop, IQueryable<T> resultOfJoin)
        {

            var Parameter = Expression.Parameter(typeof(T), "x"); //x
            PropertyInfo[] Properties = typeof(T).GetProperties(); //Get the properties of JoinResult

            string propertyname; 

            //Get the property name
            foreach(var property in Properties)
            {
               if(property.GetType() == Prop)
                  propertyname = property.Name;
            }

           //Creating a property that can be passed as a parameter to the property for Entity class.
           var expressionparameter = Expression.Property(Parameter, propertyname);  //x.Book
                var expressionproperty = Expression.Property(expressionparameter, FieldName);//x.Book.BookID
                var expressionclause = Expression.Equal(expressionproperty, Expression.Constant(Constant));//x.Book.BookID == Constant
var expressionlambda = Expression.Lambda<Func<T,bool>>(expressionclause, Parameter) 
                return resultOfJoin.Where(expressionlambda).AsQueryable();
        }

希望這可以幫助

制作擴展方法怎么樣? 像這樣:

public static class QueryExpression
{
    public static IQueryable<T> WhereWithLambdaExpression<T>(
        this IQueryable<T> query, List<Operation> OperationList)
    {
        ExpressionTree expressionTree = new ExpressionTree();
        Node Root = expressionTree.ConstructTree(OperationList);

        var Parameter = Expression.Parameter(typeof(T), "x");
        //Returns an Expression Clause by And/Or every input in OperationList
        var Expression = CalculateExpression(Root);

        //Finally creating Lambda
        Expression<Func<T, bool>> predicate =
            Expression.Lambda<Func<T, bool>>(Expression, Parameter); 

        return query.Where(predicate);
    }
}

然后

var query = joinResults.WhereWithLambdaExpression(OperationList);

編譯器可以從IQueryable<T>推斷匿名類型並將其作為T傳遞給擴展方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM