MongoDB: проблема с дочерним классом с переопределенным идентификатором и атрибутом

У меня возникают большие проблемы, когда я переопределяю свойство Id в производном классе в моей настройке хранилища MongoDB.

Базовый класс, который наследуют все мои модели данных, выглядит так:

public abstract class DataModel
{
     [BsonId]
     [BsonRepresentation(BsonType.ObjectId)]
     public virtual string Id { get; set; }

     public DateTime Created { get; set; }

     public DateTime Modified { get; set; }

     public DateTime Deleted { get; set; }
}

Затем есть несколько конкретных дочерних моделей данных, которые используют upserts. Это требует, чтобы я аннотировал переопределенное свойство Id с помощью [BsonIgnoreIfDefault] в соответствии с этим ответом:

public class ChildDataModel : DataModel
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    [BsonIgnoreIfDefault]          //  <---- need this for Upserts to work
    public override string Id { get; set; }

    ... // child-specific properties
}

Но, к сожалению, это приводит к этой ошибке:

Свойство Id типа Namespace.ChildDataModel не может использовать имя элемента _id, поскольку оно уже используется свойством Id типа Namespace.DataModel.

Я пробовал регистрировать карты классов, добавлять дискриминатор типов с RootClass = true в базовую модель, а также определять мои дочерние модели данных в базовом классе с помощью специального атрибута [BsonKnownTypes(typeof(ChildDataModel), ...)], но безрезультатно.

Что я здесь делаю не так?


person silkfire    schedule 16.04.2019    source источник
comment
Некоторое время назад я работал с унаследованными классами, в этом сценарии у меня был только Id в базовом классе, вы действительно Id в дочернем классе?   -  person Tiago Ávila    schedule 16.04.2019


Ответы (1)


Драйвер MongoDB по соглашению пытается отобразить все свойства с именем Id в _id в карте классов. Поскольку у вас есть два класса, он дважды регистрирует _id. Более того, BsonIgnoreIfDefault работал бы нормально, если бы Id был null, но здесь это не так, поскольку драйвер автоматически сгенерирует значение при вставке нового документа.

Чтобы исправить это, вы можете использовать BsonIgnore, если хотите, чтобы в MongoDB был один _id

public class ChildDataModel : DataModel
{        
    [BsonRepresentation(BsonType.ObjectId)]
    [BsonIgnore]
    public override string Id { get; set; }
}

будет храниться как:

{
    "_id" : ObjectId("5cb5fe72e2a22b3848b6a1f6"),
    "Created" : ISODate("2019-04-16T16:10:25.908Z"),
    "Modified" : ISODate("2019-04-16T16:10:25.914Z"),
    "Deleted" : ISODate("2019-04-16T16:10:25.914Z")
}

или вы можете использовать атрибут BsonNoId, если хотите, чтобы два значения сохранялись отдельно:

[BsonNoId]
public class ChildDataModel : DataModel
{        
    [BsonRepresentation(BsonType.ObjectId)]
    public override string Id { get; set; }
}

будет:

{
    "_id" : ObjectId("5cb5fecde2a22b3088ef731c"),
    "Created" : ISODate("2019-04-16T16:11:56.810Z"),
    "Modified" : ISODate("2019-04-16T16:11:56.822Z"),
    "Deleted" : ISODate("2019-04-16T16:11:56.822Z"),
    "Id" : ObjectId("5cb5fecde2a22b3088ef731c")
}

однако с точки зрения приложения значение остается прежним.

person mickl    schedule 16.04.2019
comment
К сожалению, ни одно из решений не помогло. В первом случае ReplaceOneAsync не генерирует Id. Во втором не заполняется ни _id, ни Id, оба сериализуются как null. - person silkfire; 17.04.2019
comment
@silkfire Я пробовал с Insert, думаю, в других случаях игрушке нужно сгенерировать его самостоятельно - person mickl; 17.04.2019
comment
Так что только в этой конкретной ситуации? Потому что ReplaceOneAsync с моделью, помеченной [BsonIgnoreIfDefault], работает, если вы не имеете дело с унаследованными моделями, как я здесь. - person silkfire; 17.04.2019
comment
Вместо этого я получил эту ошибку: A write operation resulted in an error. After applying the update, the (immutable) field '_id' was found to have been altered to _id: ObjectId('5cb6eb199764726f1437387e'). Не похоже, что я создаю его вручную. - person silkfire; 17.04.2019