简体   繁体   English

IQueryable表达式类型不匹配

[英]IQueryable expression type mismatch

I want to create an extension method for a LINQ expression but I'm stuck. 我想为LINQ表达式创建扩展方法,但是我遇到了麻烦。 What I need is just to create a method which will add a specific Where clause to a Queryable . 我需要的只是创建一个将特定的Where子句添加到Queryable Something like: 就像是:

var hierarchy = "a string";
Session.Query<SomeClass>.Where(x => x.Layer.Hierarchy.StartsWith(hierarchy) ||
                                    x.Layer.Hierarchy == hierarchy);

to become: 成为:

var hierarchy = "a string";
Session.Query<SomeClass>.LayerHierarchy(x => x.Layer, hierarchy);

And do that Where logic inside. 并执行其中的逻辑。 So basicly the extension method LayerHierarchy() is running over the Queryable of T but the subject is of type Layer : 因此,基本上,扩展方法LayerHierarchy()TQueryable之上运行,但是主题的类型为Layer

public static IQueryable<T> LayerHierarchy<T>(this IQueryable<T> query,
                                                  Expression<Func<T, Layer>> layer,
                                                  string hierarchy)

{
    var parameterExp = Expression.Parameter(typeof(Layer), "layer");
    var propertyExp = Expression.Property(parameterExp, "Hierarchy");

    // StartWith method
    MethodInfo methodStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
    var valueStartsWith = Expression.Constant(string.Concat(hierarchy, "|"), typeof(string));

    var methodExpStartsWith = Expression.Call(propertyExp, methodStartsWith, valueStartsWith);
    var startsWith = Expression.Lambda<Func<Layer, bool>>(methodExpStartsWith, parameterExp);

    // Equals method
    MethodInfo methodEquals = typeof(string).GetMethod("Equals", new[] { typeof(string) });
    var valueEquals = Expression.Constant(hierarchy, typeof(string));

    var methodExpEquals = Expression.Call(propertyExp, methodEquals, valueEquals);
    var equals = Expression.Lambda<Func<Layer, bool>>(methodExpEquals, parameterExp);

    return query
                .Where(startsWith)
                .Where(equals);
}

Everything works fine above the return line. return线以上,一切正常。 It complains that... 它抱怨...

Cannot convert from System.Linq.Expressions.Expression<System.Func<Layer, bool>> to System.Linq.Expressions.Expression<System.Func<T, int, bool>> 无法从System.Linq.Expressions.Expression<System.Func<Layer, bool>>System.Linq.Expressions.Expression<System.Func<T, int, bool>>

when trying to pass the expressions to query.Where() method. 尝试将表达式传递给query.Where()方法时。 How can I fix it? 我该如何解决?

Well, the problem is how you are creating the Lambda s. 好吧,问题在于您如何创建Lambda They should begin from T , not from Layer : 它们应该从T开始,而不是从Layer

var startsWith = Expression.Lambda<Func<T, bool>>(methodExpStartsWith, parameterExp);
var equals = Expression.Lambda<Func<T, bool>>(methodExpEquals, parameterExp);

However, in order for this to work, you are missing one more PropertyExpression . 但是,为了使其正常工作,您还缺少一个PropertyExpression

Your query now looks like: 您的查询现在看起来像:

(Layer)x => x.Hierarchy.StartsWith(...) (层)x => x.Hierarchy.StartsWith(...)

When, what you want is this: 什么时候,您想要的是:

(T)x => x.Layer.Hierarchy.StartsWith(...) (T)x => x.Layer.Hierarchy.StartsWith(...)

So, use this instead: 因此,请改用此:

var parameterExp = Expression.Parameter(typeof(T), "item");
var layerExp = Expression.Property(parameterExp, "Layer");
var propertyExp = Expression.Property(layerExp, "Hierarchy");

Your logic should change a little though, since two .Where will generate an AND condition between them, and it seems like you want one of them to be true ( StartsWith or Equals ), so: 但是,您的逻辑应该稍有变化,因为两个.Where会在它们之间生成一个AND条件,并且似乎您希望其中一个为真( StartsWithEquals ),因此:

var parameterExp = Expression.Parameter(typeof(T), "item");
var layerExp = Expression.Property(parameterExp, "Layer");
var propertyExp = Expression.Property(layerExp, "Hierarchy");

// StartWith method
MethodInfo methodStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
var valueStartsWith = Expression.Constant(string.Concat(hierarchy, "|"), typeof(string));

var methodExpStartsWith = Expression.Call(propertyExp, methodStartsWith, valueStartsWith);

// Equals method
MethodInfo methodEquals = typeof(string).GetMethod("Equals", new[] { typeof(string) });
var valueEquals = Expression.Constant(hierarchy, typeof(string));

var methodExpEquals = Expression.Call(propertyExp, methodEquals, valueEquals);

var orElseExp = Expression.OrElse(methodExpStartsWith, methodExpEquals);
var orElse = Expression.Lambda<Func<T, bool>>(orElseExp, parameterExp);

return query.Where(orElse);

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

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