使用表达式>作为新表达式的参数
我有一些代码当前在 SQL 中构建 In 语句。我构建一个表达式,它返回;
value(generic(list[T])).Contains(x => x.Id)
这工作得很好,所以如果我有一个对象列表;
public class ObjectToSearch
{
public int IdToSearchOn {get;set;}
}
我想搜索 ids 1、2、3,它工作得很好。我的 SQL 查询很棒。
现在,我需要搜索嵌套对象列表,所以我可能会这样做;
public class ParentObjectToSearch
{
public IEnumerable<ObjectToSearch> Objects {get;set;}
}
因此,查看我发现的一些代码(如何创建表达式树调用 IEnumerable
无法比较“System.Collections.Generic.ICollection`1”类型的元素。仅支持原始类型(例如 Int32、String 和 Guid)和实体类型。
var collectionType = GetIEnumerableImpl( forCollection.Type );
Type elementType = collectionType.GetGenericArguments( )[0];
MethodInfo method = BaseFilter.GetType( ).GetMethod( "FilterWith" );
MethodInfo genericMethod = method.MakeGenericMethod( new[] { elementType } );
return (genericMethod.Invoke( BaseFilter, null ) as LambdaExpression);
FilterWith 是我在原始过滤器上调用的方法,希望能返回我的表达式。因此,当与外部表达式结合时,我的内部表达式似乎被错误地评估。我的基本目标是(我相信);
x => x.Collection.Contains( y => new { 1, 3, 3}.Contains( y.Id));
如果我单独测试内部过滤,它工作得很好,所以我假设这就是我尝试组合元素的方式,如果我尝试使用 Contains 而不是 Any 或 All,我仍然会得到相同的错误。
我已将实体框架放入标签中,因为它被评估为针对实体集的表达式,并且有人可能有这样做的经验。
更新 经过一个晚上的思考,我想我有一个更好的问题;
我如何构建Where表达式,以便我可以构建;
x => x.Collection.Where( y => new[] { 1, 3 }.Contains( y.Id)).Count( ) > 0
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(2)
最初的错误实际上是由我试图对集合进行 null 检查这一事实引起的,这在 SQL 中肯定无法完成。
那么,Any 和 All 无法转换为 SQL 表达式,所以;
Expression<Func<TEntity, bool>> result = Expression.Lambda<Func<TEntity, bool>>(
Expression.GreaterThan(
Expression.Call( CountMethod( elementType ),
Expression.Call( WhereMethod( elementType ),
theCollectionWeAreSearching,
filter ) ),
Expression.Constant( 0 ) ), param );
elementType 是集合中元素的类型。过滤器是一个测试我的列表的表达式。检索的Count和Where方法如下;
public MethodInfo GetMethodFromEnumerable(string methodName, params Func<MethodInfo, bool>[] filters)
{
var methods = typeof( Enumerable )
.GetMethods( BindingFlags.Static | BindingFlags.Public )
.Where( mi => mi.Name == methodName );
methods = filters.Aggregate( methods, (current, filter) => current.Where( filter ) );
return methods.First( );
}
public MethodInfo WhereMethod(Type collectionType)
{
// Get the Func<T,bool> version
var getWhereMethod = GetMethodFromEnumerable( "Where",
mi => mi.GetParameters( )[1].ParameterType.GetGenericArguments( ).Count( ) == 2 );
return getWhereMethod.MakeGenericMethod( collectionType );
}
public MethodInfo CountMethod(Type collectionType)
{
var getCountMethod = GetMethodFromEnumerable( "Count" ); // There can be only one
return getCountMethod.MakeGenericMethod( collectionType );
}
我认为发生的事情是引入了如此多的新代码,导致我去寻找根本不存在的问题!
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我认为这里的问题是 EF 认为您要求它将 ObjectToSearch 发送到数据库并进行比较。换句话说,我认为您是在询问 SQL Server 某个字段中的任何值是否等于某个类的实例,这显然行不通:
我不能确定 - 这似乎是一个正在使用的具体示例问题中缺少。如果这听起来不错,请尝试在生成查询之前展平要搜索的值集:
I think that the problem here is that EF thinks that you are asking it to ship the ObjectToSearch to the database and compare on that. In other words, I think you are asking SQL Server whether any values in some field are equal to an instance of some class, which clearly won't work:
I can't be sure- it seems like a concrete example of this in use is missing from the question. If this sounds right, try flattening the set of values that you want to search on before generating the query: