简体   繁体   English

在Mongo DB中升级和Id问题

[英]Upserting in Mongo DB and the Id problem

I have a problem while upserting to mongo db using the official C# driver. 使用官方C#驱动程序向mongo db上传时遇到问题。

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

My entities already have the id-s but I had to create the mongo specific Id for it to work, as all the documents in a collection should have one. 我的实体已经拥有了id-s但我必须创建mongo特定的ID才能工作,因为集合中的所有文档都应该有一个。 Now then I receive a new entity in my system a new Mongo Id is generated and I get the mongo cannot change _id of a document old exception. 现在我在我的系统中收到一个新的实体,生成一个新的Mongo Id,我得到的mongo不能改变文件旧异常的_id Is there some work-around? 有一些解决方法吗?

Let me describe the design a bit. 让我来描述一下设计。 All the entities which would be stored as documents were inheriting from AggregateRoot which had the id generation in it. 将作为文档存储的所有实体都继承自AggregateRoot,其中包含id生成。 Every sub-document had its id generated automatically and I had no problem with this. 每个子文档都自动生成了id,我对此没有任何问题。 The id in AggregateRoot was introduced to correct the problem when retrieving data from MongoCollection to List and the generation was introduced so the id-s are different. 引入AggregateRoot中的id是为了在从MongoCollection到List检索数据时纠正问题,并且引入了生成,因此id-s不同。 Now we can move that id generation to save methods because the new entity for update had a new id generation. 现在我们可以移动id生成来保存方法,因为更新的新实体有一个新的id生成。 But it would mean that every dev on the team must not forget generating id-s in repository which is risky. 但这意味着团队中的每个开发人员都不能忘记在存储库中生成id-s,这是有风险的。 It would be nicer just to ignore the id than mapping from mongo if it is possible and not to have AggregateRoot class at all 如果可能的话,忽略id而不是从mongo映射会更好,而根本就没有AggregateRoot类

I've encountered similar problem. 我遇到过类似的问题。 I wanted to upsert documents using official C# driver. 我想使用官方C#驱动程序来插入文档。 I had a class like this: 我有一个这样的课:

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

In console I would write: db.collection.update({Field1: 3},{Field1: 3, Field2: "value"}) and it would work. 在控制台我会写: db.collection.update({Field1: 3},{Field1: 3, Field2: "value"}) ,它会工作。 In C# I wrote: 在C#中我写道:

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

and it didn't work! 它不起作用! Because driver includes empty id in update statement and when I upsert second document with different value of Field1 exception E11000 duplicate key error index is thrown (in this case Mongo tries to insert a document with _id that already exists in db). 因为驱动程序在update语句中包含空id,当我使用不同的Field1异常值插入第二个文档时,会抛出E11000 duplicate key error index (在这种情况下,Mongo尝试插入一个已经存在于db中的_id文档)。

When I generated _id by myself (like topic starter) I've encountered the same exception ( mongo cannot change _id of a document ) on upserting objects with existing value of Field1. 当我自己生成_id(比如主题启动器)时,我在遇到具有现有值Field1的对象时遇到了同样的异常( mongo cannot change _id of a document )。

Solution is to mark Id property by attribute [BsonIgnoreIfDefault] (and not initialize it). 解决方案是按属性[BsonIgnoreIfDefault]标记Id属性(而不是初始化它)。 In this case driver omits _id field in update statement and MongoDb generates Id if it necessary. 在这种情况下,驱动程序在update语句中省略_id字段,MongoDb在必要时生成Id。

Looks like you might be explicitly setting the Id value for both inserts and updates. 看起来您可能会显式设置插入和更新的Id值。 That's fine for inserts, all new objects need an _id value, however for updates you're not allowed to change the value of _id on an existing document after it's created. 这对于插入很好,所有新对象都需要_id值,但是对于更新,在创建现有文档后,不允许更改现有文档的_id值。

Try not setting the Id value at all. 尽量不要设置Id值。 If you don't specify a value before inserting, the driver uses built-in IdGenerator classes to generate a new _id value, so if it's an ObjectId type it'll use the ObjectIdGenerator . 如果在插入之前未指定值,则驱动程序使用内置的IdGenerator类生成新的_id值,因此如果它是ObjectId类型,则它将使用ObjectIdGenerator Then both your inserts and updates work fine. 然后你的插入和更新工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM