使用Expression。<factory method =“”>语法动态构建表达式树</factory>

时间:2011-02-01 09:34:02

标签: c# linq dynamic tree expression

我有以下代码来构建IQueryable

Expression<Func<TParentEntity, TChildEntity, bool>> joinExpr =
    ctx.GetJoinExpression<TParentEntity, TChildEntity>();

Expression<Func<TChildEntity, bool>> childSelectionExpression =
    GetExpression<TChildEntity>(ctx);

return
    from parentEntity in ctx.GetQueryable<TParentEntity>()
        .AsExpandable()
    let childEntities = 
        from child in ctx.GetQueryable<TChildEntity>()
        where joinExpr.Invoke(parentEntity, child)
        select child
    where childEntities.Any(childSelectionExpression)
    select parentEntity;

我一直在尝试(不成功地)构建将返回相同结果的表达式树。 我想要一个表达式Expression<Func<TParentEntity,bool> parentExpression 我可以使用如下:

from parentEntity in ctx.GetQueryable<TParentEntity>()
    .AsExpandable()
where parentExpression.Invoke(parentEntity)
select parentEntity

有人认为这是可能的吗?我相信,但我无法解决它......

2 个答案:

答案 0 :(得分:0)

我知道你想要什么,因为我已经尝试过,我很遗憾地通知你,你已经到了痛苦的世界。以下是部分解决方法:

Expression<Func<TParentEntity, TChildEntity, bool>> joinExpr =
    ctx.GetJoinExpression<TParentEntity, TChildEntity>();

Expression<Func<TChildEntity, bool>> childSelectionExpression =
    GetExpression<TChildEntity>(ctx);

return
    (from parentEntity in ctx.GetQueryable<TParentEntity>()
        .AsExpandable()
    let childEntities = 
        from child in ctx.GetQueryable<TChildEntity>()
        where joinExpr.Invoke(parentEntity, child)
        select child
    select parentEntity).Where(childSelectionExpression);

你必须转换所有使用表达式变量的查询调用,就像我做的那样。并非总是可行,但我认为在你的情况下它是。

答案 1 :(得分:0)

Eureaka: - )

这篇文章末尾的方法返回一个类型为Expression<Func<TParentEntity,bool>>的表达式,让我们称之为parentExpression。

当像这样使用时:


var data = (from parentEntity in parentEntities.AsExpandable() where parentExpression.Invoke(parentEntity) select parentEntiy).ToList()


实际发生的事情是这样的:


var data = (from parentEntity in parentEntities.AsExpandable() let childeren = childEntities.Where(c => c.parentId = parentEntity.Id) where childeren.Any([childSelectionLambda]) select parent).ToList()


能够在一个类型为λ的Lambda中表达子标准 Expression<Func<TParentEntity, bool>> 使用PredicateBuilder.And()很容易将多个子标准(表示为父标准)或其他(正常)父标准组合在一起。

EF和linq to SQL(和sql ce)的测试是绿色的: - )

override public Expression<Func<TParentEntity, bool>> 
        GetParentExpression<TParentEntity>( IDynamicQueryAdapter ctx ) 
    {

        // Define parameters needed in expresion tree
        ParameterExpression parentParameter = 
            Expression.Parameter (typeof (TParentEntity), "parent");
        ParameterExpression childParameter = 
            Expression.Parameter (typeof (TChildEntity), "child");

        // Define the IQueryable<TChildEntity> as 
        // a constant for use in the expression tree.
        IQueryable<TChildEntity> childDatasource = 
            ctx.GetQueryable<TChildEntity>().AsExpandable();
        ConstantExpression childDatasourceConstant = 
            Expression.Constant (childDatasource);

        // Get MethodInfo instance, needed for the MethodCallExpression
        MethodInfo anyMethodInfoChildEntity = 
            QueryHelper.GetQueryableAnyMethod<TChildEntity> ();

        // Get the lambda expression
        // required to select only those child entities
        // which meet the user defined criteria
        Expression<Func<TChildEntity, bool>> childSelectionExpression = 
            GetExpression<TChildEntity> (ctx);

        // Use the ExpressionParameter childParamter for the
        // ChildSelectionExpression and strip Expression.Invoke using Expand()
        Expression<Func<TChildEntity, bool>> lambda5 =
            Expression.Lambda<Func<TChildEntity, bool>> (
            Expression.Invoke (childSelectionExpression, childParameter),
                    childParameter).Expand ();


        #region Express the parent child relation
        PropertyInfo parentKeyPropertyInfo = null;
        PropertyInfo childKeyPropertyInfo = null;
        ctx.GetParentChildAssociationProperties (
            typeof (TParentEntity), typeof (TChildEntity),
            out parentKeyPropertyInfo, out childKeyPropertyInfo);
        Expression parentPropertyExpression =
            Expression.Property (parentParameter, parentKeyPropertyInfo.Name);
        Expression childPropertyExpression =
            Expression.Property (childParameter, childKeyPropertyInfo.Name);

        if( childKeyPropertyInfo.PropertyType != parentKeyPropertyInfo.PropertyType )
        {
            // TODO: what if the property types are incomparable >> exception.
            // some more code is needed!!
            Type nullableParentType = 
                typeof (Nullable<>)
                .MakeGenericType (parentKeyPropertyInfo.PropertyType);

            if( childKeyPropertyInfo.PropertyType == nullableParentType )
            {
                childPropertyExpression =
                    Expression.Convert (childPropertyExpression,
                        parentKeyPropertyInfo.PropertyType);
            }
            else if( childKeyPropertyInfo.PropertyType.IsValueType )
            {
                Type nullableChildType =
                    typeof (Nullable<>).MakeGenericType (childKeyPropertyInfo.PropertyType);
                if( parentKeyPropertyInfo.PropertyType == nullableChildType )
                {
                    parentPropertyExpression =
                        Expression.Convert (parentPropertyExpression,
                        childKeyPropertyInfo.PropertyType);
                }
            }
        } 
        #endregion
        var lambda4 = Expression.Lambda<Func<TChildEntity, bool>> (
            Expression.Equal (
                parentPropertyExpression, 
                childPropertyExpression), childParameter );

        var predicate = lambda4.And(lambda5).Expand();

        Expression<Func<TParentEntity, bool>> parentSelectionExpression = 
            Expression.Lambda<Func<TParentEntity,bool>>(
            Expression.Call (
                null, 
                anyMethodInfoChildEntity, 
                new Expression[] { childDatasourceConstant, predicate }),
            new[]{parentParameter});

        return parentSelectionExpression;
    }

注意:PredicateBuilder,扩展名AsExpandable(),扩展名Expand()...是LinqKit的一部分 有关这些访问的更多信息:Linqkit into

相关问题