C# MongoDB BsonDocument не сериализуется в пользовательский класс с помощью BsonSerializer

#c# #mongodb #serialization #bsondocument #bsonserializer

#c# #mongodb #сериализация #документ bsondocument #bsonserializer

Вопрос:

У меня возникла проблема с сериализацией документов BsonDocuments с помощью BsonSerializer.

Я использую var bsonDoc = collection.Find(...) для извлечения одного документа из базы данных MongoDB. Затем я пытаюсь сериализовать его с помощью var strongTypedDocument = BsonSerializer.Deserializelt;MainSDocumentgt;(bsonDoc);

Вот документ BsonDocument

 {   "MainSPayload" :   {   "GDeets" : { "Id" : 0, "GSerial" : "XX123XX123" }  }  }  

Вот классы C#

 [JsonObject(MemberSerialization.OptIn)] [BsonIgnoreExtraElements] public class MainSDocument {  [JsonProperty(Required = Required.Always)]  public MainState MainSPayload  {  get; set;  } }  [JsonObject(MemberSerialization.OptIn)] public class MainState  {  [JsonProperty(Required = Required.Always)]  public GDetails GDeets  {  get; set;  } }  public class GDetails  {  public int Id  {  get; set;  }   public string GSerial  {  get; set;  } }  

Ошибка, которую я получаю, заключается в следующем: FormatException: An error occurred while deserializing the GDetails property of class MainState : Element 'Id' does not match any field or property of class GDetails .'

Почему это происходит? Почему элемент не Id совпадает с элементом int Id в GDetails классе?

Комментарии:

1. пожалуйста, покажите нам класс GroupInfo

2. @Jazb ой! это была опечатка 🙂 исправил ее.

Ответ №1:

Сериализация для Id поля имеет специальный рабочий процесс, который эффективно преобразует это значение в то, как его представляет серверная сторона: _id . Чтобы обойти это, вы можете использовать:

 BsonClassMap.RegisterClassMaplt;GDetailsgt;(c =gt;  {  c.AutoMap();  c.UnmapField(u =gt; u.Id); // remove default _id workflow   c.MapField(u =gt; u.Id); // add a simple Id field  });  

или проще:

 BsonClassMap.RegisterClassMaplt;GDetailsgt;(c =gt;  {  c.AutoMap();  c.SetIdMember(null);  });  

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

 var customPack = new ConventionPack();  customPack.Add(new NoIdMemberConvention());  ConventionRegistry.Register("NoIdConvention", customPack, t =gt; t == typeof(GDetails));  

также вместо вышеперечисленного вы можете просто добавить атрибут BsonNoId в свой класс:

 [BsonNoId]  public class GDetails  {  public int Id  {  get; set;  }   public string GSerial  {  get; set;  }  }  

Комментарии:

1. Спасибо. Есть ли более общий способ установить это для всех полей идентификаторов без необходимости вводить эти 5 строк кода для каждого класса?

2. Я так не думаю, и это требуется не для каждого класса, только для случаев, когда Id средства не на стороне сервера _id

3. Смотрите вышеприведенное обновление

4. Спасибо. BsonNoId Атрибут более элегантен, имо..