Элемент 'id' не соответствует ни одному полю или свойству ошибки с вложенными классами - PullRequest
2 голосов
/ 29 марта 2019

У меня есть следующая схема документа mongodb;

{ 
    "_id" : ObjectId("5c9d34ff781318afb9e8ab43"), 
    "name" : "Name", 
    "slug" : "slug",
    "services" : {
        "subservice" : {
            "id" : NumberInt(37030)
        }
    }
}

, а затем я определяю свои классы как;

public class MainModel
{
    public ObjectId Id { get; set; }

    [BsonElement("name")]
    public string Name { get; set; }

    [BsonElement("slug")]
    public string Slug { get; set; }

    [BsonElement("services")]
    public ServicesDef Services { get; set; }

    public class ServicesDef 
    {
        [BsonElement("subservice")]
        public SubServiceDef SubService{ get; set; }

        public class SubServiceDef 
        {
            [BsonElement("id")]
            public int Id { get; set; }
        }
    }
}

Но как-то, когда я запрашиваю документ;

var result = await Repository.FindAsync(x => x.Slug == slug);

То, что services.subservice.id не зарегистрирован должным образом и получение

Элемент 'id' не соответствует ни одному полю или свойству класса SubServiceDef.

Застрял здесь и ищусовет.

Я думаю, что у меня та же проблема с , я не могу десериализовать с атрибутом "Id" , но, похоже, решение еще есть.

1 Ответ

1 голос
/ 29 марта 2019

Короче говоря: все о конвенциях.Драйвер MongoDB .NET предоставляет статический класс ConventionRegistry, который позволяет вам регистрировать собственные соглашения (подробнее здесь ).Кроме того, есть два «встроенных» соглашения __defaults__ и __attributes__.Копая глубже (драйвер github ), вы обнаружите, что в нем зарегистрировано довольно интересное соглашение:

new NamedIdMemberConvention(new [] { "Id", "id", "_id" })

Это означает, что id члены будут рассматриваться как обычные элементы BSON _id.

Как это исправить?

Вы можете избавиться от соглашений по умолчанию

ConventionRegistry.Remove("__defaults__");

Однако автоматически вы отбросите все другие соглашения драйверов, что довольно рискованно.В качестве альтернативы вы можете создать поддельное свойство, которое всегда будет пустым:

public class SubServiceDef
{
    [BsonElement("id")]
    public int Id { get; set; }

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

или вы можете просто использовать атрибут BsonNoId, который

Указывает, что IdMember класса должен быть нулевым.

[BsonNoId]
public class SubServiceDef
{
    [BsonElement("id")]
    public int Id { get; set; }
}

Таким образом, соглашение будет устанавливать ваш id как IdMember на карте классов, но затем во время постобработки этот атрибут заставит IdMember быть нулевым, и ваш класс будет успешно десериализован

...