使用表达式树使用实体框架调用.Any扩展方法

时间:2010-12-28 19:54:41

标签: c# entity-framework expression-trees

我在Calling a Method from an ExpressionMSDN查看了一些示例,但我无法为下面的查询获得Any()的正确方法调用/对象类型。我似乎能够获得属性调用,但不能获得子属性的IEnumerable部分 billing_map_set_lu是billmaps_lu的父级,并在实体框架中定义为关联。

我使用表达式树的原因是 我需要能够在运行时使用1-n .SelectMany(p => p.billmaps_lu).Where(谓词)子句定义查询。所以我想我是否可以构建表达式树,我可以处理我对这个系统的所有不同组合,这些组合很多。

var myResults = ctx.billing_map_set_lu
                   .Where(p => p.billmaps_lu.Any(b => b.billmap_columnname == "templatesittings_key" &&  b.billmap_columnvalue == 428264))
                                   SelectMany(p => p.billmaps_lu)
                   .Where (b =>b.billmap_columnname =="locations_key" && b.billmap_columnvalue == 12445)
                                   Select(z => z.billing_map_set_lu);

我尝试使用上面的示例进行了不少尝试...

ParameterExpression bms = Expression.Parameter(typeof(billmaps_lu));
Expression left1 = Expression.Property(bms, typeof(billmaps_lu).GetProperty("billmap_columnname"));
Expression right1 = Expression.Constant("templatesittings_key", typeof(string));
Expression InsideAny1 = Expression.Equal(left1, right1);
Expression left2 = Expression.Property(bms, typeof(billmaps_lu).GetProperty("billmap_columnvalue"));
Expression right2 = Expression.Constant(428264, typeof(int));
Expression InsideAny2 = Expression.Equal(left2, right2);
Expression myWhereClause1 = Expression.AndAlso(InsideAny1, InsideAny2);

上面的部分似乎很好,但是当我尝试做的时候.Any就像我无法获得正确的属性/方法来获取正确的对象。 (我觉得我在处理一个物理问题,我正在使用错误的单位。)我希望它是一个简单的我想念的东西,我对表达树很新。我已经包含了非工作代码来尝试告诉你我的头在哪里以及某人如何引导我朝着正确的方向前进。

MethodInfo method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(billing_map_set_lu).GetProperty("billmaps_lu").PropertyType);
ParameterExpression billMapSetParameter = Expression.Parameter(typeof(billing_map_set_lu), "p");
ParameterExpression billMaps = Expression.Parameter(typeof(billmaps_lu), "p1");
var myFunction = Expression.Lambda<Func<billmaps_lu, bool>>(Expression.Call(method, Expression.Property(billMapSetParameter, typeof(billing_map_set_lu).GetProperty("billmaps_lu")), myWhereClause1), billMaps)

1 个答案:

答案 0 :(得分:0)

免责声明,我没有任何已编译的工作代码。

2个问题。

第一个问题可能在于:

ParameterExpression billMapSetParameter = Expression.Parameter(typeof(billing_map_set_lu), "p");

这不是您需要的参数:

Expression.Lambda<Func<billmaps_lu, bool>>(Expression.Call(method, Expression.Property(**billMapSetParameter**, typeof(billing_map_set_lu).GetProperty("billmaps_lu")), myWhereClause1), billMaps)

将billMapSetParameter更改为billMaps ParamterExpression,那么你应该好好去。您正在调用PropertyExpression从ParameterExpression获取billMapSet。

第二个问题:(不确定,但我的直觉) 您可能需要将Where子句作为ConstantExpression传递,类型为Expression&lt; .Func&lt;&gt;&gt;。任何方法都有两个参数,其中第二个是Expression&lt; .Func&lt;&gt;&gt; (或者只是一个Func&lt;&gt;?不记得了。)

var whereExpression = Expression.Lambda<.Func<.billmaps_lu, bool>>(myWhereClause1, bms);
var ce = Expression.Constant(whereExpression)

然后将ce传回原来你“myWhereClause1”所在的地方。

交叉手指可以正常使用

编辑 - 废话,显示MI ZEH CODEZ

public class Foo
{
    public List<string> Strings { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Func<Foo, bool> func =
            a => a.Strings.Any(b => b == "asdf");

        // b => b == "asdf";
        var bParameter = Expression.Parameter(typeof (string));
        var asdfConstant = Expression.Constant("asdf");
        var compare = Expression.Equal(bParameter, asdfConstant);
        var compareExpression = Expression.Lambda<Func<string, bool>>(compare, bParameter);
        var ceCompareExpression = Expression.Constant(compareExpression.Compile());

        // a => a.Strings.Any(compareExpression)
        var parameter = Expression.Parameter(typeof (Foo));

        var foosProperty = Expression.Property(parameter, typeof (Foo).GetProperty("Strings"));
        MethodInfo method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(string));

        var anyMethod = Expression.Call(method, foosProperty, ceCompareExpression);

        var lambdaExpression = Expression.Lambda<Func<Foo, bool>>(anyMethod, parameter);

        // Test.
        var foo = new Foo {Strings = new List<string> {"asdf", "fdsas"}};

        Console.WriteLine(string.Format("original func result: {0}", func(foo)));
        Console.Write(string.Format("constructed func result: {0}", lambdaExpression.Compile()(foo)));

        Console.ReadKey();
    }
}