我有一个MongoDB集合,其中包含三个不同类(A,B,C)的文档,这些类都继承自公共类D.
使用官方C#驱动程序,我插入了所有三种类型(A,B,C)的文档,它们都与_t鉴别器一起正确显示,并且在我的代码中,他们的类映射已经注册。
如果我发出LINQ查询,如下所示(使用VB):
dim Result = database.GetCollection("mycol").AsQueryable(Of C).Where(some where clause)
如果算上这个结果,我收到一个错误“元素'来自A类的元素名称'与C类的任何字段或属性都不匹配。”
判别器是不是要在AsQueryable(Of C)
代码中启用?当我发出.Count
我的Where子句(特定于C类元素)时,它似乎被应用于A,B和C的文档。
我尝试添加.OfType(Of C)
但没有效果,尝试首先使用.ToList
转换为列表,但我仍然遇到同样的错误。有任何想法吗?
作为背景,我的客户端代码通常会处理类型为D的对象.A,B,C共享从D继承的许多常见属性,我想将索引放在上面,因此我将它们放在一个集合中。但是,偶尔我需要在特殊情况下直接引用类型A,B或C的对象。
答案 0 :(得分:12)
使用多态类型层次结构时,集合变量和LINQ查询应该从基类开始。例如,要从数据库中读取所有类型A的文档,您将编写:
var collection = database.GetCollection<D>("mycol");
var query = collection.AsQueryable<D>().OfType<A>();
foreach (var a in query)
{
// process document of type A
}
出于诊断目的,您可以使用以下命令查看相应的本机MongoDB查询:
var json = ((MongoQueryable<A>)query).GetMongoQuery().ToJson();
请注意,您必须将查询转换为MongoQueryable&lt; A&gt; (不是MongoQueryable&lt; D&gt;)因为OfType()调用改变了IQueryable的类型。
答案 1 :(得分:2)
使用.AsQueryable<D>().OfType<C>.
这应该有效地自动包含鉴别器。问题是我们不一定知道您对A,B和C使用相同的集合,因此不知道当您执行AsQueryable<C>()
时,我们实际上需要添加一个鉴别器。我们将研究如何在未来使其更加无缝。
答案 2 :(得分:1)
就我而言,我需要能够检索A,B以及基类D.所有这些都存储在同一个集合中。这就是我最终在我的存储库中所做的事情:
Shared Sub New() BsonClassMap.RegisterClassMap(Of D)( Sub(f) f.AutoMap() f.SetIsRootClass(True) End Sub) BsonClassMap.RegisterClassMap(Of A)() BsonClassMap.RegisterClassMap(Of B)() End Sub
这有效地将基类和子类添加到鉴别器中。
_t: D, A
然后允许我查询这两种类型。
Dim collection = _db.GetCollection(of D)("Items") Dim resultA = collection.AsQueryable().OfType(of A) ' Only type A's Dim resultB = collection.AsQueryable().OfType(of B) ' Only type B's Dim resultD = collection.AsQueryable().OfType(of D) ' Both A's and B's as the base class
答案 3 :(得分:0)
我遇到了同样的问题:.AsQueryable()和OfType()都不会在查询中产生“_t”鉴别器。特别是当你有一个高级通用的OpenQuery()方法时,你可以将IQueryable接口暴露给任何插件,而不需要Mongo驱动程序库引用。无论如何,如果使用静态类来访问你的集合,告诉BsonClassMap特定的类是root将解决这个问题。
// Data Repository class
public static class MyDataRepositoryMethods
{
static MyDataRepositoryMethods()
{
BsonClassMap.RegisterClassMap<MyBaseClassOfStuff>(x =>
{
x.AutoMap();
x.SetIsRootClass(true);
});
}
/// <summary>
/// Returns a queryable data sample collection
/// </summary>
/// <typeparam name="TMyBaseClassOfStuff"></typeparam>
/// <returns></returns>
public static IQueryable<TMyBaseClassOfStuff> OpenQuery<TMyBaseClassOfStuff>() where TMyBaseClassOfStuff: MyBaseClassOfStuff
{
using (var storage = new MongoDataStorageStuff())
{
// _t discriminator will reflect the final class, not the base class (unless you pass generic type info of the base class
var dataItems = storage.GetCollection<TMyBaseClassOfStuff>("abcdef").OfType<TMyBaseClassOfStuff>();
return dataItems ;
}
}
}
答案 4 :(得分:0)
我使用的是C#驱动程序v1.9.2但似乎这是在v1.4.1中引入的。
collection = MongoDatabase.GetCollection<MyBaseClass>("MyCollectionName");
long count = collection.AsQueryable().OfType<MyDerivedClass>().Count();
个人资料包含:
command: {
"count" : "MyCollectionName",
"query" : {
"_t" : "D" // MyDerivedClass discriminator value
}
}