代码之家  ›  专栏  ›  技术社区  ›  Roland Ebner

为实体框架多对多关系构建表达式树?

  •  -1
  • Roland Ebner  · 技术社区  · 7 年前

    我正在为以下结构编写代码:
    3张桌子

    表“Book”、“BookAuthor”和“Author”。

    现在,我想构建一个ExpressionTree以获得以下Linq结果:

    _ent.Book.Where(c => c.BookAuthor.Any(cd => cd.Author.AuthorName == "test"));
    

    我的问题是最后一个表达式 cd.Author.AuthorName (或类似)。

    我的当前代码:

    private MethodCallExpression BuiltMethodCall(IQueryable _query, string CustTypeID, Type _ParentObjType,
    Type _ChildObjType, string strChildObj, string strChildCol)
        {
    
            //This function will build a dynamic linq expression tree representing the ling calls of:
            //Book.Where(c => c.BookAuthor.Any(cd => cd.Author = custTypeID))
    
            ConstantExpression value = Expression.Constant(CustTypeID);
    
            //Build the outer part of the Where clause
            ParameterExpression parameterOuter = Expression.Parameter(_ParentObjType, "c");
            MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);
    
            //Build the comparison inside of the Any clause
            ParameterExpression parameterInner = Expression.Parameter(_ChildObjType, "cd");
            MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);
    
            BinaryExpression comparison = Expression.Equal(propertyInner, value);
            LambdaExpression lambdaInner = Expression.Lambda(comparison, parameterInner);
    
            //Create Generic Any Method
            Func<MethodInfo, bool> methodLambda = m => m.Name == "Any" && m.GetParameters().Length == 2;
            MethodInfo method = typeof(Enumerable).GetMethods().Where(methodLambda).Single()
                .MakeGenericMethod(_ChildObjType);
    
            //Create the Any Expression Tree and convert it to a Lambda
            MethodCallExpression callAny = Expression.Call(method, propertyOuter, lambdaInner);
            LambdaExpression lambdaAny = Expression.Lambda(callAny, parameterOuter);
    
            //Build the final Where Call
            MethodCallExpression whereCall = Expression.Call(typeof(Queryable), "Where",
                new Type[] { _query.ElementType }, new Expression[]
                {
                        _query.Expression,
                        Expression.Quote(lambdaAny)
                });
    
            return whereCall;
        }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Ivan Stoev    7 年前

    如果我理解正确,您会问如何创建嵌套的属性访问器表达式。

    有了 String.Split Enumerable.Aggregate 方法。

    下面是一个自定义扩展方法,可以用作 Expression.Property 方法替换:

    public static partial class ExpressionExtensions
    {
        public static MemberExpression Property(this Expression instance, string path)
        {
            return (MemberExpression)path.Split('.').Aggregate(instance, Expression.Property);
        }
    }
    

    它可以正确处理中编码的简单属性和嵌套属性 string 具有 . 分离器(例如。 "BookAuthor" "Author.AuthorName" ).

    因此

    MemberExpression propertyOuter = Expression.Property(parameterOuter, strChildObj);
    

    MemberExpression propertyInner = Expression.Property(parameterInner, strChildCol);
    

    您可以安全使用

    MemberExpression propertyOuter = parameterOuter.Property(strChildObj);
    

    MemberExpression propertyInner = parameterInner.Property(strChildCol);