带C#的MongoDB:使用自定义谓词查找元素

带C#的MongoDB:使用自定义谓词查找元素,c#,mongodb,generics,lambda,mongodb-.net-driver,C#,Mongodb,Generics,Lambda,Mongodb .net Driver,我有一个MongoDB数据库,其中有几个集合,每个集合存储特定类型的对象。我试图实现一个泛型选择函数,根据类型对特定集合进行操作,如以下定义所示: object[] Select<T>(Func<T, bool> condition) 这段代码可以编译,但当我尝试运行它时,会得到一个带有 Additional information: Unsupported filter: Invoke(value(System.Func`2[Person,System

我有一个MongoDB数据库,其中有几个集合,每个集合存储特定类型的对象。我试图实现一个泛型选择函数,根据类型对特定集合进行操作,如以下定义所示:

object[] Select<T>(Func<T, bool> condition)
这段代码可以编译,但当我尝试运行它时,会得到一个带有

Additional information: Unsupported filter:        
Invoke(value(System.Func`2[Person,System.Boolean]), {document}).
在阅读了API文档之后,我的印象是,通常不可能使用抽象类型的lambda表达式(如上面的示例中所示),而只能使用
FilterDefinitionBuilder
Gt()
Eq()
等。
我很好奇我是否正确理解了这一点,或者确实存在使用抽象谓词查询集合的可能性(我对MongoDB C#driver很陌生)。

确定可以使用Lambda表达式作为参数。驱动程序会将您的表达式转换为简单的过滤器,不可能翻译每个表达式,但如果可能的话,它会工作。 我真的不明白你在样本中做什么,你没有使用你的条件

函数不应使用Func,而应使用表达式作为参数:

public static T[] Select<T>(IMongoCollection<T> collection,  
                             Expression<Func<T, bool>> condition)
{
    if (typeof(T) == typeof(Person))
    {
         return collection.AsQueryable().Where(condition).ToArray();
    }
    return null;
}
如图所示,如果只想查询所有项目,可以通过以下方式进行:

return this.collectionPersons.Find(p=>true).ToArray();
您必须提及使用中的所有名称空间:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;
using MongoDB.Driver;
using MongoDB.Driver.Linq;

我的错误在于如何调用谓词。 下面是它的工作示例:

public object[] SelectByPredicate<T>(Func<T, bool> predicate)
{
    if (typeof(T) == typeof(Person))
    {
        Func<Person, bool> f = (Person p) => 
        {
            T t = (T)Convert.ChangeType(p, typeof(T));
            return predicate(t);
        };

        return this.SelectPersonsByPredicate(f);
    }
    else if (typeof(T) == typeof(Pet))
    {
        Func<Pet, bool> f = (Pet p) => 
        {
            T t = (T)Convert.ChangeType(p, typeof(T));
            return predicate(t);
        };

        return this.SelectPetsByPredicate(f);
    }
    else
    {
        throw new NotSupportedException("Type not supported");
    }
}

private Person[] SelectPersonsByPredicate(Func<Person, bool> predicate)
{
    return this.collectionPersons.AsQueryable().Where(predicate).ToArray();
}

private Pet[] SelectPetsByPredicate(Func<Pet, bool> predicate)
{
    return this.collectionPets.AsQueryable().Where(predicate).ToArray();
}
public对象[]SelectByPredicate(Func谓词)
{
如果(类型(T)=类型(人))
{
Func f=(个人p)=>
{
T=(T)Convert.ChangeType(p,typeof(T));
返回谓词(t);
};
返回此参数。SelectPersonsByPredicate(f);
}
否则如果(类型(T)=类型(Pet))
{
Func f=(宠物p)=>
{
T=(T)Convert.ChangeType(p,typeof(T));
返回谓词(t);
};
返回此值。选择PetsByPredicate(f);
}
其他的
{
抛出新的NotSupportedException(“类型不受支持”);
}
}
私人[]SelectPersonsByPredicate(Func谓词)
{
返回此.collectionPersons.AsQueryable().Where(谓词).ToArray();
}
私有Pet[]选择PETSBYPREDICATE(Func谓词)
{
返回此.collectionPets.AsQueryable().Where(谓词).ToArray();
}
然后,如果您需要谓词的一个子集,您只需编写如下内容

object[] personsSelected    = db.SelectByPredicate<Person>(p=>p.Name.Contains("Theo"));
object[]personselected=db.SelectByPredicate(p=>p.Name.Contains(“Theo”);
我承认,它不是很优雅,因为它返回一个
对象[]
,而不是
T[]
,但在所有实际应用中,它都是可以的。
如果有人知道更好的方法,我会感兴趣的。

谢谢Maksim,我试着实现表达式而不是谓词,正如您所建议的那样。以下错误是我得到的:MongoDB.Driver.Linq.IMongoQueryable'不包含“Where”的定义,并且最佳扩展方法重载“System.Linq.Queryable.Where(System.Linq.IQueryable,System.Linq.Expressions.Expression)”具有一些无效参数。我自然不会以这种方式查询所有项目,“returntrue;”这只是一个最简单的例子,但无论如何都不起作用。我现在已经尝试过了,通过这个方法,我可以查询我的收藏。@AlexKonnen也许你缺少一些使用语句?Maksim,我不这么认为:已检查:所有提到的都存在…检查你的驱动程序版本。where是MongoDB.Driver.Linq中的extesion方法的定义(检查是否在usings中有)。别忘了它把表达式作为一个参数,在你的问题中f不是一个表达式,如果你想这样使用它,你应该改变类型
public object[] SelectByPredicate<T>(Func<T, bool> predicate)
{
    if (typeof(T) == typeof(Person))
    {
        Func<Person, bool> f = (Person p) => 
        {
            T t = (T)Convert.ChangeType(p, typeof(T));
            return predicate(t);
        };

        return this.SelectPersonsByPredicate(f);
    }
    else if (typeof(T) == typeof(Pet))
    {
        Func<Pet, bool> f = (Pet p) => 
        {
            T t = (T)Convert.ChangeType(p, typeof(T));
            return predicate(t);
        };

        return this.SelectPetsByPredicate(f);
    }
    else
    {
        throw new NotSupportedException("Type not supported");
    }
}

private Person[] SelectPersonsByPredicate(Func<Person, bool> predicate)
{
    return this.collectionPersons.AsQueryable().Where(predicate).ToArray();
}

private Pet[] SelectPetsByPredicate(Func<Pet, bool> predicate)
{
    return this.collectionPets.AsQueryable().Where(predicate).ToArray();
}
object[] personsSelected    = db.SelectByPredicate<Person>(p=>p.Name.Contains("Theo"));