I need to store enums
as string in MongoDB
, which is fine, but I need to able to handle changes within the enum
.
For example, if you have the following enum
enum CarType {
SportCar,
Suv,
Hatchback
}
If I delete SUV and I try to load a record from MongoDB
that is of CarType
SUV, it will throw an exception, because it is unable to map it back to enum
from the string
. I need to be able to handle this gracefully, like have an enum
value unknown and use that as a fall back value.
Is there a way to specify a custom mapper for only specify columns within MongoDB
? For example the car entity has multiple string
values, but only the CarType
which is an enum
in our back end and stored as string
in our MongoDB
. So when loading data from DB
, use a customer mapper only for the CarType
property that will not throw and exception, instead map it to CarType.Unkown
CodePudding user response:
First you need to define the unknown enum as the first enum. I myself prefer storing them as explicit ints to prevent renaming of enums corrupt the database, but that is not nessecary in your case.
enum CarType {
Unknown
SportCar,
Suv,
Hatchback
}
Then you need to write and register a custom deserializer for your enum in order to implement the fallback to "unknown" as this. It will try to parse your database value to the enum and fallbacks to default (Unknown) if unable to parse it.
public class CustomEnumSerializer<TEnum> : MongoDB.Bson.Serialization.Serializers.EnumSerializer<TEnum>
where TEnum : struct
{
public override TEnum Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var type = context.Reader.GetCurrentBsonType();
string val;
switch (type)
{
case BsonType.String:
val = context.Reader.ReadString() ?? "";
break;
case BsonType.Int32:
val = context.Reader.ReadInt32().ToString();
break;
case BsonType.Int64:
val = context.Reader.ReadInt64().ToString();
break;
case BsonType.Null:
return default(TEnum);
default:
return base.Deserialize(context, args);
}
if (Enum.TryParse(val, true, out TEnum result) && Enum.IsDefined(typeof(TEnum), result))
{
return result;
}
return default(TEnum);
}
}
Register the custom serializer as:
BsonClassMap.RegisterClassMap<ClassThatHoldsTheProperty>(ms =>
{
ms.AutoMap();
ms.GetMemberMap(i => i.CarTypeProperty)
.SetSerializer(new CustomEnumSerializer<CarType>());
});