Gibt es eine Möglichkeit, Enums als Zeichenfolgennamen und nicht als Ordnungswerte zu speichern?
Beispiel:
Stellen Sie sich vor, ich habe diese Aufzählung:
public enum Gender
{
Female,
Male
}
Nun, wenn ein imaginärer Benutzer mit existiert
...
Gender gender = Gender.Male;
...
Es wird in der MongoDb-Datenbank als {... "Geschlecht": 1 ...} gespeichert
aber ich würde so etwas bevorzugen {... "Geschlecht": "Männlich" ...}
Ist das möglich? Benutzerdefiniertes Mapping, Reflexionstricks, was auch immer.
Mein Kontext: Ich verwende stark typisierte Sammlungen über POCO (nun, ich markiere ARs und verwende gelegentlich Polymorphismus). Ich habe eine dünne Abstraktionsschicht für den Datenzugriff in Form von Unit Of Work. Ich serialisiere / deserialisiere also nicht jedes Objekt, sondern kann (und tue) einige ClassMaps definieren. Ich benutze den offiziellen MongoDb-Treiber + Fluent-Mongodb.
quelle
Antworten:
Mit dem MongoDB .NET-Treiber können Sie Konventionen anwenden , um zu bestimmen, wie bestimmte Zuordnungen zwischen CLR-Typen und Datenbankelementen behandelt werden.
Wenn Sie möchten, dass dies auf alle Ihre Aufzählungen angewendet wird, müssen Sie Konventionen nur einmal pro AppDomain einrichten (normalerweise beim Starten Ihrer Anwendung), anstatt allen Typen Attribute hinzuzufügen oder jeden Typ manuell zuzuordnen:
// Set up MongoDB conventions var pack = new ConventionPack { new EnumRepresentationConvention(BsonType.String) }; ConventionRegistry.Register("EnumStringConvention", pack, t => true);
quelle
using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using Newtonsoft.Json; using Newtonsoft.Json.Converters; public class Person { [JsonConverter(typeof(StringEnumConverter))] // JSON.Net [BsonRepresentation(BsonType.String)] // Mongo public Gender Gender { get; set; } }
quelle
Sie können die Klassenzuordnung für die Klasse anpassen, die die Aufzählung enthält, und angeben, dass das Mitglied durch eine Zeichenfolge dargestellt werden soll. Dies behandelt sowohl die Serialisierung als auch die Deserialisierung der Aufzählung.
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); }); }
Ich suche immer noch nach einer Möglichkeit, anzugeben, dass Aufzählungen global als Zeichenfolgen dargestellt werden sollen, aber dies ist die Methode, die ich derzeit verwende.
quelle
Verwenden Sie MemberSerializationOptionsConvention , um eine Konvention zum Speichern einer Aufzählung zu definieren.
new MemberSerializationOptionsConvention(typeof(Gender), new RepresentationSerializationOptions(BsonType.String))
quelle
Mit Treiber 2.x habe ich mit einem bestimmten Serializer gelöst :
BsonClassMap.RegisterClassMap<Person>(cm => { cm.AutoMap(); cm.MapMember(c => c.Gender).SetSerializer(new EnumSerializer<Gender>(BsonType.String)); });
quelle
Ich habe festgestellt, dass es in einigen Fällen nicht ausreicht , nur die Antwort von Ricardo Rodriguez anzuwenden , um die Enum-Werte für die Zeichenfolge in MongoDb ordnungsgemäß zu serialisieren:
// Set up MongoDB conventions var pack = new ConventionPack { new EnumRepresentationConvention(BsonType.String) }; ConventionRegistry.Register("EnumStringConvention", pack, t => true);
Wenn Ihre Datenstruktur beinhaltet, dass Enum-Werte in Objekte gepackt werden, verwendet die MongoDb-Serialisierung das Set nicht
EnumRepresentationConvention
zum Serialisieren.Wenn Sie sich die Implementierung des ObjectSerializer des MongoDb-Treibers ansehen , wird der Boxwert
TypeCode
(Int32
für Aufzählungswerte) aufgelöst und dieser Typ zum Speichern Ihres Aufzählungswerts in der Datenbank verwendet. Boxed Enum-Werte werden also alsint
Werte serialisiert . Sie bleiben auchint
bei der Deserialisierung als Werte erhalten.Um dies zu ändern, können Sie eine benutzerdefinierte
ObjectSerializer
Datei schreiben , die die Menge erzwingt,EnumRepresentationConvention
wenn der umrahmte Wert eine Aufzählung ist. Etwas wie das:public class ObjectSerializer : MongoDB.Bson.Serialization.Serializers.ObjectSerializer { public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) { var bsonWriter = context.Writer; if (value != null && value.GetType().IsEnum) { var conventions = ConventionRegistry.Lookup(value.GetType()); var enumRepresentationConvention = (EnumRepresentationConvention) conventions.Conventions.FirstOrDefault(convention => convention is EnumRepresentationConvention); if (enumRepresentationConvention != null) { switch (enumRepresentationConvention.Representation) { case BsonType.String: value = value.ToString(); bsonWriter.WriteString(value.ToString()); return; } } } base.Serialize(context, args, value); } }
Legen Sie dann den benutzerdefinierten Serializer als den für die Serialisierung von Objekten zu verwendenden fest:
BsonSerializer.RegisterSerializer(typeof(object), new ObjectSerializer());
Auf diese Weise wird sichergestellt, dass die Aufzählungswerte in Kästchen genauso wie die nicht in Kästchen verpackten Zeichenfolgen gespeichert werden.
Beachten Sie jedoch, dass beim Deserialisieren Ihres Dokuments der Wert in der Box eine Zeichenfolge bleibt. Es wird nicht wieder in den ursprünglichen Aufzählungswert konvertiert. Wenn Sie die Zeichenfolge wieder in den ursprünglichen Aufzählungswert konvertieren müssen, muss wahrscheinlich ein Unterscheidungsfeld in Ihr Dokument eingefügt werden, damit der Serializer weiß, in welchen Aufzählungstyp derrialisiert werden soll.
Eine Möglichkeit wäre, ein bson-Dokument anstelle einer Zeichenfolge zu speichern, in dem das Unterscheidungsfeld (
_t
) und ein Wertefeld (_v
) zum Speichern des Aufzählungstyps und seines Zeichenfolgenwerts verwendet werden.quelle
Die hier veröffentlichten Antworten funktionieren gut für
TEnum
undTEnum[]
funktionieren jedoch nicht mitDictionary<TEnum, object>
. Sie können dies erreichen, wenn Sie den Serializer mithilfe von Code initialisieren. Ich wollte dies jedoch über Attribute tun. Ich habe eine flexible Datei erstelltDictionarySerializer
, die mit einem Serializer für den Schlüssel und den Wert konfiguriert werden kann.public class DictionarySerializer<TDictionary, KeySerializer, ValueSerializer> : DictionarySerializerBase<TDictionary> where TDictionary : class, IDictionary, new() where KeySerializer : IBsonSerializer, new() where ValueSerializer : IBsonSerializer, new() { public DictionarySerializer() : base(DictionaryRepresentation.Document, new KeySerializer(), new ValueSerializer()) { } protected override TDictionary CreateInstance() { return new TDictionary(); } } public class EnumStringSerializer<TEnum> : EnumSerializer<TEnum> where TEnum : struct { public EnumStringSerializer() : base(BsonType.String) { } }
Verwendung wie diese, bei der sowohl Schlüssel als auch Wert Aufzählungstypen sind, aber eine beliebige Kombination von Serialisierern sein können:
[BsonSerializer(typeof(DictionarySerializer< Dictionary<FeatureToggleTypeEnum, LicenseFeatureStateEnum>, EnumStringSerializer<FeatureToggleTypeEnum>, EnumStringSerializer<LicenseFeatureStateEnum>>))] public Dictionary<FeatureToggleTypeEnum, LicenseFeatureStateEnum> FeatureSettings { get; set; }
quelle
Am Ende habe ich Aufzählungselementen Werte zugewiesen, wie von Chris Smith in einem Kommentar vorgeschlagen:
Nicht genau das, wonach ich gesucht habe, aber es scheint, dass es keinen anderen Weg gibt.
quelle
Wenn Sie .NET Core 3.1 und höher verwenden, verwenden Sie den neuesten ultraschnellen Json Serializer / Deserializer von Microsoft, System.Text.Json ( https://www.nuget.org/packages/System.Text.Json ).
Den Metrikvergleich finden Sie unter https://medium.com/@samichkhachkhi/system-text-json-vs-newtonsoft-json-d01935068143
using System; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using System.Text.Json.Serialization;; public class Person { [JsonConverter(typeof(JsonStringEnumConverter))] // System.Text.Json.Serialization [BsonRepresentation(BsonType.String)] // MongoDB.Bson.Serialization.Attributes public Gender Gender { get; set; } }
quelle