简体   繁体   English

如何动态构建表达式树以用于匿名类型

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

This is my first post here.这是我在这里的第一篇文章。 If I've broken any guidelines, please let me know and I'll be happy to correct them.如果我违反了任何准则,请告诉我,我很乐意纠正它们。

I have the following entity classes:我有以下实体类:

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

And a second entity class as such,还有第二个实体类,

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

I also have this function to generate a lambda expression dynamically based on user input.我也有这个函数可以根据用户输入动态生成一个 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
        }


Operation class contains details about the type of operation, field and values.操作类包含有关操作类型、字段和值的详细信息。 It gets passed from the client which I'm using the query against the Entity classes by mapping field names.它从客户端传递,我通过映射字段​​名称对实体类使用查询。

code works as intended when used this way,以这种方式使用时,代码按预期工作,

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

OR或者

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

I'm trying to Join two Entity classes using LINQ but I can't seem to find a way to dynamically create a Lambda Expression for the generated Anonymous type that is returned by the JOIN.我正在尝试使用 LINQ 加入两个实体类,但我似乎无法找到一种方法来为由 JOIN 返回的生成的匿名类型动态创建 Lambda 表达式。

My join looks like,我的加入看起来像,

 var result = from c in _BookContext.Books

              join d in _LibraryContext.Library

              on c.BookID equals d.ID

              select new { c , d };

However, this won't work for obvious reasons,但是,由于明显的原因,这不起作用,

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

Passing 'object' or 'dynamic' to the GetLambdaExpression() doesn't work because the field names are not pre-defined and it throws an exception.将“对象”或“动态”传递给 GetLambdaExpression() 不起作用,因为字段名称不是预定义的,并且会引发异常。

How could I construct an Expression Tree for an Anonymous type.如何为匿名类型构建表达式树。

Many thanks.非常感谢。

UPDATE更新

I managed to fix it.我设法解决了它。 Here's what I did:这是我所做的:

Instead of storing the result of a join into an Anonymous type, I created a new class which has objects of the Entity classes used to perform the join.我没有将联接的结果存储到匿名类型中,而是创建了一个新类,该类具有用于执行联接的实体类的对象。

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

Perform the join and store the data into JoinResult执行连接并将数据存储到 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 };

Finally, here's the trick to dynamically create the Lambda Expression for JoinResult.最后,这是为 JoinResult 动态创建 Lambda 表达式的技巧。

I created an Expression Parameter for JoinResult, then created Expression Properties for the Properties of JoinResult.我为 JoinResult 创建了一个表达式参数,然后为 JoinResult 的属性创建了表达式属性。

I used the Expression Properties created to be used as Parameters to be passed into a new Property for the Entity class.我使用创建的表达式属性作为参数传递给实体类的新属性。 Essentially, creating a property in the format of "x.Book.BookID".本质上,以“x.Book.BookID”格式创建属性。

For instance, if I wanted to perform a EqualOperation on JoinResult.例如,如果我想对 JoinResult 执行 EqualOperation。 Here is how I would do it.这是我将如何做到的。

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

Hope this helps希望这可以帮助

What about making an extension method?制作扩展方法怎么样? Like this:像这样:

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

Then然后

var query = joinResults.WhereWithLambdaExpression(OperationList);

The compiler can infer the anonymous type from IQueryable<T> and pass it as T to the extension method.编译器可以从IQueryable<T>推断匿名类型并将其作为T传递给扩展方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM