2012-07-22 17 views
4

我有一個單一的MongoDB集合持有三種不同的類別(A,B,C),這都來自一個共同的D類放大器使用C#MongoDB的LINQ與鑑別

根據官方的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的對象。

回答

2

使用.AsQueryable<D>().OfType<C>.這應該有效地自動包含鑑別器。問題是我們不一定知道你使用的是A,B和C的相同集合,因此不知道當你做AsQueryable<C>()時,我們實際上需要添加一個鑑別器。我們將研究如何在未來實現更加無縫。

+0

克雷格您好,感謝這麼多的快速答覆。很遺憾沒有區別。正如我在原來的帖子中提到的那樣,我曾嘗試過,但它似乎沒有改變任何東西。是否有驅動程序隨附的診斷程序,例如是否有可能看到底層查詢?就像你可以用一個查詢對象(即Query.ToString) – 2012-07-22 03:21:19

+0

我也嘗試了'AsQueryable()。OfType(Of C)'而不是'AsQueryable(Of C).OfType(Of C)'並且得到了「No強制運算符定義在類型'MongoDB.Bson.BsonDocument'和'C'之間' – 2012-07-22 03:26:47

+0

還有一點評論:)我詢問診斷的原因是我可以使用IMongoQuery發出幾乎相同的命令,並且得到正確的結果。我試圖使用泛型爲我的非MongoDB意識類組成一個通用查詢方法,因此LINQ適合這個賬單。 – 2012-07-22 03:30:38

9

使用多態類型層次結構時,您的集合變量和LINQ查詢應該以基類開始。例如,閱讀類型的所有文件,從數據庫中的回你可以這樣寫:

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的類型。

+0

這工作,謝謝你! – 2012-07-28 02:08:48

+2

神奇的塊的信息。我鼓勵你將它添加到mongodb文檔中的Polymorphism部分(或者指出它是否已經存在) - 我知道我可以使用它。 – 2012-09-20 22:33:11

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 
0

我遇到了同樣的問題:.AsQueryable()和OfType()會在查詢中產生一個「_t」鑑別符。特別是當你有一個高級別的通用OpenQuery()方法時,你可以將IQueryable接口暴露給任何插件,而不需要它們需要Mongo驅動程序庫引用。無論如何,如果使用靜態類訪問您的集合,告訴BsonClassMap特定的類是根將解決此問題。

// 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 ; 
     } 
    } 
} 
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 
    } 
}