2011-09-02 6 views
13

公式C#ドライバを使用してmongo dbにアップデート中に問題が発生しました。Mongo DBのアップデートとIdの問題

public abstract class AggregateRoot 
{ 
    /// <summary> 
    /// All mongoDb documents must have an id, we specify it here 
    /// </summary> 
    protected AggregateRoot() 
    { 
     Id = ObjectId.GenerateNewId(); 
    } 

    [BsonId] 
    public ObjectId Id { get; set; } 
} 

私の実体はすでにID-Sを持っているが、私は、コレクション内のすべてのドキュメントが1つを持っている必要があるとして、それを動作させるためにMongoの特定のIDを作成する必要がありました。今では私のシステムで新しいエンティティを受け取って、新しいMongo Idが生成されて、mongoは文書の古い_idを変更できません。例外。回避策はありますか?

デザインを少し説明しましょう。ドキュメントとして格納される であるすべてのエンティティは、その中に というIDを生成したAggregateRootから継承していました。すべてのサブ文書にはidが自動的に で生成されていましたが、問題はありませんでした。 MongoCollectionからListにデータを取得するときにAggregateRootのID が導入され、id-s が異なるように生成が導入されました。今度は、更新のための新しいエンティティが新しいID生成を持っていたので、そのID生成をメソッド を保存するように移動できます。しかし、 は、チームのすべての開発者が危険なリポジトリ内のID- を生成することを忘れてはならないことを意味します。それはちょうどそれが可能であればモンゴからのマッピングよりID を無視して、あなたが明示的に挿入と更新の両方にId値を設定する可能性があるように見えるすべての

+0

どのようにオブジェクトを保存していますか? BsonId属性はMongoDBにあなたのidとしてそのフィールドを使用させるべきです。 –

+0

考えられるのは、データが外部システムからストレージに送られるということです。それは私が保管しなければならない独自のIDを持っています。そして、これはMongoとの互換性のための偽のIDです。すべてのドキュメントはAggregateRootを継承しているので、すべてのオブジェクトを受け取ると生成されます。私は同じデータを受け取るかもしれないが、生成されたmongo idは異なっていることは明らかです。だから例外が表示されます –

答えて

8

で AggregateRootクラスを持っていないよりよいだろう。挿入には問題ありませんが、すべての新しいオブジェクトには_idの値が必要ですが、更新のために、作成後に既存の文書の_idの値を変更することはできません。

Idの値を設定しないでください。挿入する前に値を指定しない場合、ドライバは組み込みのIdGeneratorクラスを使用して新しい_id値を生成します。したがって、ObjectId型の場合はObjectIdGeneratorを使用します。次に、挿入と更新の両方が正常に動作します。

+0

私はidプロパティを削除する場合、実際にはエンティティを保存/更新することは問題ではありません。問題は、_idを存在しないプロパティにマップできないため、コードからコレクションを検索しようとすると例外がスローされることです。 –

+2

コレクションに '{BsonIgnoreExtraElements}'属性を使用すると、一致するプロパティがあります。 –

50

同様の問題が発生しました。 公式のC#ドライバを使用してドキュメントをアップサートしたかったのです。私が書くでしょうコンソールで

public class MyClass 
{ 
    public ObjectId Id { get; set; } 
    public int Field1 { get; set; } 
    public string Field2 { get; set; } 
} 

db.collection.update({Field1: 3},{Field1: 3, Field2: "value"})、それが働くだろう、私はこのようなクラスを持っていました。 C#で私は書いた:

collection.Update(Query.EQ("Field1", 3), 
       Update.Replace(new MyClass { Field1 = 3, Field2 = "value" }), 
       UpdateFlags.Upsert); 

それは動作しませんでした!ドライバは空文字IDを更新ステートメントに含み、Field1例外の異なる値を持つ2番目の文書をアップシュートすると、E11000 duplicate key error indexがスローされます(この場合、Mongoはデータベースに既に存在する_idを持つ文書を挿入しようとします)。

自分で_idを作成したとき(トピックスターターのように)、Field1の既存の値を持つオブジェクトをアップセルするのと同じ例外(mongo cannot change _id of a document)が発生しました。

解決策は、属性[BsonIgnoreIfDefault]でIdプロパティにマークを付ける(初期化しない)ことです。この場合、ドライバはupdate文で_idフィールドを省略し、必要ならばMongoDbがIdを生成します。

+8

あなたは、[BsonIgnoreIfDefault]がかなりの時間を節約したという人を支配します。私はあなたのためにもっと投票することができるのは残念です。 –

+2

私のReplaceOneAsync呼び出しが2.0ドライバで動作していなかった理由を突き止めようと約1時間を無駄にしました。この答えが見つかりました。 [BsonIgnoreIfDefault]を追加し、問題を解決しました。ありがとう! – BrandonLWhite

+1

私はこれを理解するのに何時間も費やしました。ありがとう! – bbrez1