IQueryable 表达式类型不匹配
IQueryable expression type mismatch
我想为 LINQ 表达式创建一个扩展方法,但我被卡住了。我需要的只是创建一个方法,将特定的 Where 子句添加到 Queryable
。类似于:
var hierarchy = "a string";
Session.Query<SomeClass>.Where(x => x.Layer.Hierarchy.StartsWith(hierarchy) ||
x.Layer.Hierarchy == hierarchy);
成为:
var hierarchy = "a string";
Session.Query<SomeClass>.LayerHierarchy(x => x.Layer, hierarchy);
并执行其中的逻辑。所以基本上扩展方法 LayerHierarchy()
是 运行 在 T
的 Queryable
上但是主题是类型 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);
}
return
行以上一切正常。它抱怨...
Cannot convert from System.Linq.Expressions.Expression<System.Func<Layer, bool>>
to System.Linq.Expressions.Expression<System.Func<T, int, bool>>
当试图将表达式传递给 query.Where()
方法时。我该如何解决?
嗯,问题在于您如何创建 Lambda
。它们应该从 T
开始,而不是从 Layer
:
var startsWith = Expression.Lambda<Func<T, bool>>(methodExpStartsWith, parameterExp);
var equals = Expression.Lambda<Func<T, bool>>(methodExpEquals, parameterExp);
但是,为了让它起作用,您还缺少一个 PropertyExpression
。
您的查询现在看起来像:
(Layer)x => x.Hierarchy.StartsWith(...)
什么时候,你要的是这个:
(T)x => x.Layer.Hierarchy.StartsWith(...)
所以,改用这个:
var parameterExp = Expression.Parameter(typeof(T), "item");
var layerExp = Expression.Property(parameterExp, "Layer");
var propertyExp = Expression.Property(layerExp, "Hierarchy");
你的逻辑应该稍微改变一下,因为两个 .Where
会在它们之间生成一个 AND
条件,而且你似乎希望其中一个为真(StartsWith
或 Equals
), 所以:
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);
我想为 LINQ 表达式创建一个扩展方法,但我被卡住了。我需要的只是创建一个方法,将特定的 Where 子句添加到 Queryable
。类似于:
var hierarchy = "a string";
Session.Query<SomeClass>.Where(x => x.Layer.Hierarchy.StartsWith(hierarchy) ||
x.Layer.Hierarchy == hierarchy);
成为:
var hierarchy = "a string";
Session.Query<SomeClass>.LayerHierarchy(x => x.Layer, hierarchy);
并执行其中的逻辑。所以基本上扩展方法 LayerHierarchy()
是 运行 在 T
的 Queryable
上但是主题是类型 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);
}
return
行以上一切正常。它抱怨...
Cannot convert from
System.Linq.Expressions.Expression<System.Func<Layer, bool>>
toSystem.Linq.Expressions.Expression<System.Func<T, int, bool>>
当试图将表达式传递给 query.Where()
方法时。我该如何解决?
嗯,问题在于您如何创建 Lambda
。它们应该从 T
开始,而不是从 Layer
:
var startsWith = Expression.Lambda<Func<T, bool>>(methodExpStartsWith, parameterExp);
var equals = Expression.Lambda<Func<T, bool>>(methodExpEquals, parameterExp);
但是,为了让它起作用,您还缺少一个 PropertyExpression
。
您的查询现在看起来像:
(Layer)x => x.Hierarchy.StartsWith(...)
什么时候,你要的是这个:
(T)x => x.Layer.Hierarchy.StartsWith(...)
所以,改用这个:
var parameterExp = Expression.Parameter(typeof(T), "item");
var layerExp = Expression.Property(parameterExp, "Layer");
var propertyExp = Expression.Property(layerExp, "Hierarchy");
你的逻辑应该稍微改变一下,因为两个 .Where
会在它们之间生成一个 AND
条件,而且你似乎希望其中一个为真(StartsWith
或 Equals
), 所以:
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);