2017-03-02 83 views
0

我移植从旧的遗留MongoDB的司机一些代码,使用新的驱动程序,并已触及问题查询派生类型的值。我有一个包含来自公共基类的多个派生类型的集合。以前,我能够使用派生类属性查询集合(这是使用基类型声明的),并只检索派生类文档。所以考虑到这些类:使用MongoDB的C#驱动

[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. 

这是不再使用新的驱动程序?我们有类允许通用查询这个集合,我现在看不到任何优雅的方法。

编辑:

可悲的是独立的集合是我们混合过滤器表达式拉回使用相同的查询不同类型的非首发。在“猫狗”例如从上面这样的:

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(); 

我会看看“nameof”上述方法 - 可工作,但它似乎的老办法优雅缺乏给我。 ..

任何帮助,非常感谢!

感谢,

史蒂夫

+1

除了Maksim的回答下面,在新API中有一个OfType()方法... IMongoCollection dogs = db.GetCollection (“Animals”)。OfType ()。 –

回答

3

你有猫,狗的集合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(); 

编辑

我这里补充克雷格·威尔逊评论,非常感兴趣的信息(感谢,克雷格):

新的API中

有一个OfType()方法...

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

OK,这似乎工作:

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(); 

虽然我认为它缺乏旧的驱动方法的风采。

+1

这与我向您建议的解决方案完全相同,那里出了什么问题? –

+0

没有什么是错的,我发布这个具体的答案作为一个确认的解决方案,感谢您的帮助。 –