带C#的MongoDB:使用自定义谓词查找元素
我有一个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
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"));