2011-09-02 59 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,但我不得不爲它創建工作蒙戈特定ID,作爲一個集合中的所有文件應該有一個。現在,然後我收到一個新的實體,在我的系統中生成了一個新的Mongo Id,並且我得到了mongo不能更改_id文檔舊異常的。有一些解決方法嗎?

讓我來描述一下設計。所有將作爲文檔存儲的實體 都從AggregateRoot繼承,該AggregateRoot在其中生成了ID號 。每個子文檔的ID都自動生成了 ,我對此沒有任何問題。引入AggregateRoot 中的id是爲了解決從 MongoCollection到List中的數據檢索時出現的問題,並引入了生成,因此id-s 與此不同。現在我們可以移動該id代以保存方法 ,因爲用於更新的新實體具有新的id代。但它意味着團隊中的每個開發人員都不能忘記在存儲庫中生成id-s ,這是有風險的。這將是更好的只是忽略ID 比蒙戈映射,如果有可能,而不是有 AggregateRoot類在所有

+0

你是如何保存你的對象? BsonId屬性應該強制MongoDB使用該字段作爲你的id。 –

+0

這個想法是,數據來自外部系統的存儲。它有自己的ID,我必須存儲。爲了兼容Mongo,這是一個僞造的ID。每個文檔都從AggregateRoot繼承,所以這個東西是在接收每個對象時生成的。很明顯,我可能會收到相同的數據,但生成的mongo id不同。所以例外出現 –

回答

8

看起來你可能會明確地設置兩個插入和更新的Id值。對插入來說沒問題,所有新對象都需要_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); 

它沒有工作!由於驅動程序在update語句中包含空id,並且當我使用不同值的Field1異常向上插入第二個文檔時,會引發E11000 duplicate key error index(在這種情況下,Mongo會嘗試插入帶有已存在於db中的_id的文檔)。

當我自己生成_id(如主題啓動程序)時,我在遇到現有值爲Field1的對象上插入時遇到了同樣的異常(mongo cannot change _id of a document)。

解決方案是標記Id屬性的屬性[BsonIgnoreIfDefault](而不是初始化它)。在這種情況下,驅動程序省略了update語句中的_id字段,如果必要的話,MongoDb會生成Id。

+8

你統治的人,[BsonIgnoreIfDefault]節省了大量的時間。這是一個恥辱,我可以爲你投多一票。 –

+2

浪費了大約一個小時,試圖找出爲什麼我的ReplaceOneAsync與2.0驅動程序調用不起作用。找到了這個答案。添加了[BsonIgnoreIfDefault]並解決了問題。謝謝! – BrandonLWhite

+1

我花了數小時試圖弄清楚這一點。謝謝! – bbrez1