7

すべて共通のクラス D から継承する 3 つの異なるクラス (A、B、C) のドキュメントを保持する単一の MongoDB コレクションがあります。

公式の C# ドライバーを使用して、3 つのタイプ (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 から継承された多くの共通プロパティを共有するため、それらを 1 つのコレクションに配置します。ただし、場合によっては、特殊な状況で型 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();

OfType() 呼び出しによって IQueryable の型が変更されたため、クエリを MongoQueryable<A> (MongoQueryable<D> ではない) にキャストする必要があることに注意してください。

于 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(真)
            終了サブ)

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

    サブ終了

これにより、基本クラスとサブクラスの両方がディスクリミネーターに効果的に追加されます。

_t:D、A

これにより、両方のタイプを照会できます。

Dim コレクション = _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 と B の両方を基本クラスとして
于 2012-09-20T23:24:31.140 に答える
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 に答える
0

私は同じ問題に遭遇しました: .AsQueryable() も OfType() も、クエリで「_t」識別子を生成しません。特に、Mongo ドライバー ライブラリの参照を必要とせずに IQueryable インターフェイスを任意のプラグインに公開できるように、高レベルの汎用 OpenQuery() メソッドがある場合。とにかく、コレクションにアクセスするために静的クラスを使用している場合、特定のクラスがルートであることを 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 ;
        }
    }
}
于 2014-11-19T19:40:32.380 に答える