7

我有一个 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特定于 C 类元素的 Where 子句时,它正在应用于 A、B 和 C 的文档。

我尝试添加.OfType(Of C)但没有效果,尝试先使用 转换为列表.ToList,但我继续收到相同的错误。有任何想法吗?

作为背景,我的客户端代码通常会处理 D 类型的对象。A、B、C 共享许多从 D 继承的公共属性,我想在这些属性上放置索引,因此我将它们放在一个集合中。但是,有时我需要在特殊情况下直接引用 A、B 或 C 类型的对象。

4

5 回答 5

15

使用多态类型层次结构时,您的集合变量和 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<A>(而不是 MongoQueryable<D>),因为 OfType() 调用更改了 IQueryable 的类型。

于 2012-07-24T15:24:42.017 回答
2

使用.AsQueryable<D>().OfType<C>. 这应该有效地自动包含鉴别器。问题是我们不一定知道您对 A、B 和 C 使用相同的集合,因此不知道当您这样做时AsQueryable<C>(),我们实际上需要添加一个鉴别器。我们将研究如何在未来使其更加无缝。

于 2012-07-22T02:23:16.597 回答
1

就我而言,我需要能够检索基类 A、B 以及 D。所有这些都存储在同一个集合中。这就是我最终在我的存储库中所做的:

    共享子 New()
        BsonClassMap.RegisterClassMap(Of D)(
            子(f)
                f.AutoMap()
                f.SetIsRootClass(True)
            结束子)

        BsonClassMap.RegisterClassMap(Of A)()
        BsonClassMap.RegisterClassMap(Of B)()

    结束子

这有效地将基类和子类都添加到了鉴别器中。

_t:D,A

然后允许我查询这两种类型。

Dim collection = _db.GetCollection(of D)("Items")

Dim resultA = collection.AsQueryable().OfType(of A) ' 仅类型 A
Dim resultB = collection.AsQueryable().OfType(of B) ' 仅类型 B
Dim resultD = collection.AsQueryable().OfType(of D) ' A's 和 B's 作为基类
于 2012-09-20T23:24:31.140 回答
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 ;
        }
    }
}
于 2014-11-19T19:40:32.380 回答
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
  }
}
于 2014-12-23T17:55:15.243 回答