繁体   English   中英

使用表达式 <Func<T,bool> &gt;作为新表达式的参数

[英]Using Expression<Func<T,bool>> as parameter for new expression

我有一些代码,目前在SQL中构建一个In语句。 我构建一个表达式,它返回;

value(generic(list[T])).Contains(x => x.Id)

这工作正常,所以如果我有一个对象列表;

public class ObjectToSearch 
{
  public int IdToSearchOn {get;set;}
}

我想搜索ID 1,2,3,它工作得很好。 我的SQL查询很棒。

现在,我需要搜索嵌套对象列表,所以我可能会这样做;

public class ParentObjectToSearch 
{
  public IEnumerable<ObjectToSearch> Objects {get;set;}
}

所以,看一下我发现的一些代码( 如何创建一个调用IEnumerable <TSource> .Any(...)的表达式树? )我想我可以调整方法,并将调用包装到Any或All,它会工作。 这很有效,直到我真的来测试数据库,我得到了;

无法比较'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,我仍然会得到相同的错误。

我已经将Entity Framework放在标签中,因为它被评估为针对实体集的表达式,并且有人可能有这样做的经验。

更新有一个晚上想一想,我想我有一个更好的问题;

如何构建Where表达式,以便构建;

x => x.Collection.Where(y => new [] {1,3} .Contains(y.Id))。Count()> 0

我认为这里的问题是EF认为你要求它将ObjectToSearch发送到数据库并进行比较。 换句话说,我认为你问SQL Server某个字段中的任何值是否等于某个类的实例,这显然不起作用:

// This won't work because it is asking EF to generate a SQL value equivalent to some class instance
((List<ParentObjectToSearch>)someList).Contains(x => x.Id)

我无法确定 - 这个问题中似乎缺少一个使用它的具体例子。 如果这听起来是正确的,请在生成查询之前尝试展平要搜索的值集:

// Assuming var outerList = some List<ParentObjectToSearch>
// this un-nests the IDs, so they can be sent to SQL Server as integers
// (which can be converted to a CONTAINS or = clause)
var listOfUnNestedIDs = outerList.SelectMany(po=>po.Objects.Select(o=>o.IdToSearchOn));

最初的错误实际上是由于我试图对集合进行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 );
        }

我认为发生的事情是引入了如此多的新代码导致我找到没有任何问题的问题!

暂无
暂无

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

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