【问题标题】:Using C# MongoDB LINQ with discriminator将 C# MongoDB LINQ 与鉴别器一起使用
【发布时间】:2014-12-24 01:55:15
【问题描述】:

我有一个 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 类型的对象。

【问题讨论】:

    标签: c# linq mongodb discriminator


    【解决方案1】:

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

    【讨论】:

    • 大量信息。我鼓励您将其添加到 mongodb 文档中的多态性部分(或者如果它已经存在则指向它)——我知道我可以使用它。
    【解决方案2】:

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

    【讨论】:

    • 嗨,克雷格,非常感谢您的快速回答。不幸的是没有区别。正如我原来的帖子中提到的那样,我已经尝试过了,但它似乎并没有改变任何东西。驱动程序是否有任何诊断信息,例如是否可以查看基础查询?就像您可以使用 Query 对象(即 Query.ToString)
    • 我还尝试了 AsQueryable().OfType(Of C) 而不是 AsQueryable(Of C).OfType(Of C) 并得到“在 'MongoDB.Bson.BsonDocument' 和 'C' 类型之间没有定义强制运算符
    • 还有一条评论 :) 我询问诊断的原因是我可以使用 IMongoQuery 发出几乎相同的命令,并且得到正确的结果。我正在尝试使用泛型为我的非 MongoDB 感知类编写一个通用查询方法,因此 LINQ 符合要求。
    • 是的,对不起......看起来格式在我的答案中杀死了大于和小于符号(我应该检查一下)。罗伯特更好地格式化了他的答案。
    • 嗨,克雷格,谢谢你 - 你的修正答案和罗伯特的答案让我重回正轨。
    【解决方案3】:

    就我而言,我需要能够检索基类 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 作为基类

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题:.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 ;
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        我使用的是 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
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多