Подтвердить что ты не робот

Хранение имен как строк в MongoDB

Есть ли способ сохранить Enums как имена строк, а не порядковые значения?

Пример:

Представьте, что у меня есть это перечисление:

public enum Gender
{
    Female,
    Male
}

Теперь, если какой-то мнимый Пользователь существует с

...
Gender gender = Gender.Male;
...

он будет храниться в базе данных MongoDb как {... "Пол": 1...}

но я бы предпочел что-то вроде этого {... "Пол": "Мужчина"...}

Возможно ли это? Пользовательское сопоставление, трюки с отражением, что угодно.

Мой контекст: я использую строго типизированные коллекции над POCO (ну, я отмечаю AR и иногда использую полиморфизм). У меня тонкий уровень абстракции доступа к данным в форме Unit Of Work. Поэтому я не сериализую/десериализую каждый объект, но могу (и делать) определять некоторые ClassMaps. Я использую официальный драйвер MongoDb + flu-mongodb.

4b9b3361

Ответ 1

Драйвер MongoDB.NET позволяет применять соглашения, чтобы определить, как обрабатываются определенные сопоставления между типами CLR и элементами базы данных.

Если вы хотите, чтобы это применимо ко всем вашим перечислениям, вам нужно только настроить соглашения один раз в AppDomain (обычно при запуске приложения), а не добавлять атрибуты ко всем вашим типам или вручную сопоставлять каждый тип:

// Set up MongoDB conventions
var pack = new ConventionPack
{
    new EnumRepresentationConvention(BsonType.String)
};

ConventionRegistry.Register("EnumStringConvention", pack, t => true);

Ответ 2

using MongoDB.Bson;

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public class Person
{
    [JsonConverter(typeof(StringEnumConverter))]  // JSON.Net
    [BsonRepresentation(BsonType.String)]         // Mongo
    public Gender Gender { get; set; }
}

Ответ 3

Вы можете настроить карту классов для класса, содержащего перечисление, и указать, что элемент будет представлен строкой. Это будет обрабатывать как сериализацию, так и десериализацию перечисления.

if (!MongoDB.Bson.Serialization.BsonClassMap.IsClassMapRegistered(typeof(Person)))
      {
        MongoDB.Bson.Serialization.BsonClassMap.RegisterClassMap<Person>(cm =>
         {
           cm.AutoMap();
           cm.GetMemberMap(c => c.Gender).SetRepresentation(BsonType.String);

         });
      }

Я все еще ищу способ указать, что перечисления будут глобально представлены как строки, но это метод, который я использую в настоящее время.

Ответ 4

Используйте MemberSerializationOptionsConvention, чтобы определить соглашение о том, как будет сохранено перечисление.

new MemberSerializationOptionsConvention(typeof(Gender), new RepresentationSerializationOptions(BsonType.String))

Ответ 5

В итоге я назначил значения элементам перечисления, как это предложил Крис Смит в комментарии:

Я бы избегал этого. Строковое значение занимает больше места, чем целое число. Однако я бы хотел, чтобы при сохранении упорства давали детерминированные значения каждому элементу в вашем перечислении, поэтому Female = 1, Male = 2, поэтому, если перечисление будет добавлено позднее или изменится порядок элементов, в результате чего вы не столкнетесь с проблемами.

Не совсем то, что я искал, но, похоже, нет другого пути.

Ответ 6

С драйвером 2.x я решил с помощью определенного сериализатора:

BsonClassMap.RegisterClassMap<Person>(cm =>
            {
                cm.AutoMap();
                cm.MapMember(c => c.Gender).SetSerializer(new EnumSerializer<Gender>(BsonType.String));
            });