使用MongoDB C#驱动程序查询派生类型值

时间:2017-03-02 12:15:56

标签: c# .net mongodb mongodb-.net-driver

我从旧的MongoDB驱动程序移植一些代码以使用新驱动程序并遇到问题。我有一个集合,其中包含来自公共基类的多个派生类型。以前我能够使用派生类属性查询集合(使用基类型声明),并只检索派生类文档。所以给出这些类:

[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(Cat),typeof(Dog))]
class Animal
{
    [BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
    public string Id { get; set; }

    public string Name { get; set; }
}

class Cat : Animal
{
    public bool LikesFish { get; set; }
}

class Dog : Animal
{
    public string FavouriteBone { get; set; }
}
然后我可以做类似的事情:

MongoCollection<Animal> animals = db.GetCollection<Animal>("Animals");
var q = Query<Cat>.EQ(c => c.LikesFish, true);
var catsThatLikeFish = animals.FindAs<Animal>(q).ToList();

工作得很好。

现在我必须输入过滤器,不能再编译:

IMongoCollection<Animal> animals = db.GetCollection<Animal>("Animals");
var query = Builders<Cat>.Filter.Eq(c => c.LikesFish, true);
var catsThatLikeFish = animals.FindSync(query);

并收到此错误:

Error CS0411 The type arguments for method 'IMongoCollection<Animal>.FindSync<TProjection>(FilterDefinition<Animal>, FindOptions<Animal, TProjection>, CancellationToken)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

使用新驱动程序不再可能吗?我们有一些类允许对这个集合进行通用查询,我现在无法看到任何优雅的方法。

编辑:

遗憾的是,单独的集合是非首发的,因为我们混合使用相同的查询来过滤表达式以回退不同的类型。在&#34;猫和狗&#34;上面的例子是这样的:

var catQuery = Query<Cat>.EQ(c => c.LikesFish, true);
var dogQuery = Query<Dog>.EQ(c => c.FavouriteBone, "Beef");
var q = Query.Or(catQuery, dogQuery);

var catsThatLikeFishOrDogsThatLikeBeef = animals.FindAs<Animal>(q).ToList();

我会看到&#34;的名字&#34;上面的方法 - 这可能有用,但它似乎缺乏旧方式的优雅......

非常感谢任何帮助!

谢谢,

史蒂夫

2 个答案:

答案 0 :(得分:4)

你有一群猫和狗togetehr你想过滤猫?或者你想要所有的狗和只有喜欢鱼的猫吗?

在第一种情况下,我建议查询只有猫或只有来自该系列的狗:

var collectionAsCats = db.GetCollection<Cat>("Animal");
var collectionAsDogs = db.GetCollection<Dog>("Animal");

var catsDoesntlikeFish = collectionAsCats.Find(c => c.LikesFish == false).ToList();
var dogs = collectionAsDogs.Find(c => c.FavouriteBone == "bla").ToList();

或者您可以拥有一个动物集合并使用字符串查询您的数据:

var collectionAll = db.GetCollection<Animal>("Animal");
var filter = Builders<Animal>.Filter.Eq(nameof(Cat.LikesFish), false);
var catsDoesntlikeFish = collectionAll.Find(filter).As<Animal>().ToList();

如果你想让猫和狗一起,你可以扩展这个过滤器:

var collectionAll = db.GetCollection<Animal>("Animal");
var filter = Builders<Animal>.Filter.Eq(nameof(Cat.LikesFish), false);
var exists = Builders<Animal>.Filter.Exists(nameof(Cat.LikesFish), false);
var orFilter = Builders<Animal>.Filter.Or(filter, exists);
var catsDoesntlikeFishAndDogs = collectionAll.Find(orFilter).ToList();

修改

我在这里添加了Craig Wilson的评论,非常感兴趣的信息(谢谢,Craig):

在新API中有一个OfType()方法......

IMongoCollection<Dog> dogs = db.GetCollection<Animal>("Animals").OfType<Dog>()

答案 1 :(得分:0)

好的,这确实有效:

var catQuery = Builders<Animal>.Filter.Eq(nameof(Cat.LikesFish), true);
var dogQuery = Builders<Animal>.Filter.Eq(nameof(Dog.FavouriteBone), "Beef");
var query = Builders<Animal>.Filter.Or(catQuery, dogQuery);
var catsThatLikeFishOrDogsThatLikeBeef = animals.FindSync(query).ToList();

虽然我确实认为它缺乏旧司机方法的优雅。