我正在尝试构建包含表达式。
private Expression<Func<T, bool>> Contains<T>(string property, IEnumerable<dynamic> values, T item)
{
ParameterExpression pe = Expression.Parameter(item.GetType(), "c");
Expression columnNameProperty = Expression.Property(pe, property);
var someValueContain = Expression.Constant(values, values.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(Guid));
Expression expression = Expression.Call(someValueContain, "Contains", new Type[] { }, convertExpression);
return Expression.Lambda<Func<T, bool>>(expression, pe);
}
在运行时我得到了这个例外。
“类型上没有方法'包含' 'System.Data.Linq.DataQuery`1 [System.Object的]'“。
灵魂就是将值参数转换为列表
private Expression<Func<T, bool>> Contains<T>(string property, IEnumerable<dynamic> values, T item)
{
ParameterExpression pe = Expression.Parameter(item.GetType(), "c");
Expression columnNameProperty = Expression.Property(pe, property);
Guidvalues = values.Cast<Guid>().ToList();
var someValueContain = Expression.Constant(Guidvalues, Guidvalues.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(Guid));
Expression expression = Expression.Call(someValueContain, "Contains", new Type[] { }, convertExpression);
return Expression.Lambda<Func<T, bool>>(expression, pe);
}
值列表超过10000的问题因此性能很低而且我得到了这个异常
“传入的请求参数太多。服务器支持a 最多2100个参数。减少参数数量并重新发送 请求。“
我有任何方法可以构建动态lambda表达式,生成类似于此查询的
select * from x where id in (select id from y)
答案 0 :(得分:3)
这只是语法糖让你变得更好:)
问题是Contains
确实不是DataQuery<T>
上的方法 - 它是System.Linq.Queryable
中的静态方法。 C#编译器通过扩展方法为您处理这个问题,但这只是C#编译器 - 它不是IL的一个特性,它是C#的一个特性。因此,当您操纵表达树或发出原始IL时,您必须自己处理它:
private Expression<Func<T, bool>> Contains<T, V>
(string property, IQueryable<V> values, T item)
{
ParameterExpression pe = Expression.Parameter(item.GetType(), "c");
Expression columnNameProperty = Expression.Property(pe, property);
var someValueContain = Expression.Constant(values, values.GetType());
var convertExpression = Expression.Convert(columnNameProperty, typeof(V));
Expression expression =
Expression.Call
(
(
((Expression<Func<bool>>)
(() => Queryable.Contains(default(IQueryable<V>), default(V)))
)
.Body as MethodCallExpression).Method,
someValueContain,
convertExpression
);
return Expression.Lambda<Func<T, bool>>(expression, pe);
}
我也避免在LINQ查询中使用dynamic
- 你使用它的方式,它并不比拥有IEnumerable<object>
更好,如果你希望它始终是Guid
无论如何,只是让它通用:)
此方法假定列的任何类型都可以转换为您传递的可枚举项的类型,当然,它适用于任何类型,而不仅仅是Guid
。
但是,这不会解决您的第二个问题 - 它非常明确。你传递的可枚举的物品太多了。除非您的LINQ提供程序有更好的传递值的方法,否则您将不得不求助于将查询拆分为多个单独的查询,每个查询都用于例如1000个项目,然后将结果重新加入。除非当然,我的猜测是正确的,你传递的values
实际上也是一个可查询的 - 在这种情况下,代码应该可以正常工作。
修改强>
我找到了获得正确MethodInfo
的最佳方法是一组这样的方法:
public static MethodInfo Method<TR>(Expression<Func<TR>> expression)
{
return (expression.Body as MethodCallExpression).Method;
}
public static MethodInfo Method<T1, TR>(Expression<Func<T1, TR>> expression)
{
return (expression.Body as MethodCallExpression).Method;
}
(自动生成的方式与实际的Func<...>
代表相同)
这样可以简化方法信息:
Method((IQueryable<T> queryable, T item) => queryable.Contains(item))
或者(为了避免产生所有可能的重载):
Method(() => default(IQueryable<T>).Contains(default(T)))