类型 'System.Data.Linq.DataQuery`1[System.Object]' 上不存在方法 'Contains'
No method 'Contains' exists on type '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);
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);
}
在 运行 时我遇到了这个异常。
"No method 'Contains' exists on type
'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,因此性能很低,我遇到了这个异常
"The incoming request has too many parameters. The server supports a
maximum of 2100 parameters. Reduce the number of parameters and resend
the request."
我有什么方法可以动态构建像这个查询一样生成的 lambda 表达式
select * from x where id in (select id from y)
这只是让你变得更好的语法糖:)
问题是 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
。
但是,这不会解决您遇到的 second 问题 - 它非常明确。您传递的可枚举项太多了。除非您的 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)))
我正在尝试构建包含表达式。
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);
}
在 运行 时我遇到了这个异常。
"No method 'Contains' exists on type '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,因此性能很低,我遇到了这个异常
"The incoming request has too many parameters. The server supports a maximum of 2100 parameters. Reduce the number of parameters and resend the request."
我有什么方法可以动态构建像这个查询一样生成的 lambda 表达式
select * from x where id in (select id from y)
这只是让你变得更好的语法糖:)
问题是 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
。
但是,这不会解决您遇到的 second 问题 - 它非常明确。您传递的可枚举项太多了。除非您的 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)))