C# - 从 MongoDB 加载数据(存储为字符串的枚举)如果不能映射回枚举则抛出异常,例如旧的枚举值已被删除
C# - Loading data (enum stored as string) from MongoDB throw exception if cannot be mapped back to enum, for example old enum value has been deleted
我需要将 enums
作为字符串存储在 MongoDB
中,这很好,但我需要能够处理 enum
.
中的更改
例如,如果您有以下枚举
enum CarType {
SportCar,
Suv,
Hatchback
}
如果我删除 SUV 并尝试从 MongoDB
加载 CarType
SUV 的记录,它将引发异常,因为它无法将其映射回 enum
来自 string
。我需要能够优雅地处理这个问题,比如有一个 enum
值未知并将其用作后备值。
有没有办法为 MongoDB
中的指定列指定自定义映射器?例如,汽车实体有多个 string
值,但只有 CarType
在我们的后端是一个 enum
并在我们的 MongoDB
中存储为 string
。因此,当从 DB
加载数据时,仅对不会抛出异常的 CarType
属性 使用客户映射器,而不是将其映射到 CarType.Unkown
首先您需要将未知枚举定义为第一个枚举。我自己更喜欢将它们存储为显式整数,以防止重命名枚举破坏数据库,但在您的情况下这不是必需的。
enum CarType {
Unknown
SportCar,
Suv,
Hatchback
}
然后您需要为您的枚举编写并注册一个自定义反序列化器,以便像这样实现对“未知”的回退。它会尝试将您的数据库值解析为枚举,如果无法解析则回退到默认值(未知)。
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);
}
}
将自定义序列化程序注册为:
BsonClassMap.RegisterClassMap<ClassThatHoldsTheProperty>(ms =>
{
ms.AutoMap();
ms.GetMemberMap(i => i.CarTypeProperty)
.SetSerializer(new CustomEnumSerializer<CarType>());
});
我需要将 enums
作为字符串存储在 MongoDB
中,这很好,但我需要能够处理 enum
.
例如,如果您有以下枚举
enum CarType {
SportCar,
Suv,
Hatchback
}
如果我删除 SUV 并尝试从 MongoDB
加载 CarType
SUV 的记录,它将引发异常,因为它无法将其映射回 enum
来自 string
。我需要能够优雅地处理这个问题,比如有一个 enum
值未知并将其用作后备值。
有没有办法为 MongoDB
中的指定列指定自定义映射器?例如,汽车实体有多个 string
值,但只有 CarType
在我们的后端是一个 enum
并在我们的 MongoDB
中存储为 string
。因此,当从 DB
加载数据时,仅对不会抛出异常的 CarType
属性 使用客户映射器,而不是将其映射到 CarType.Unkown
首先您需要将未知枚举定义为第一个枚举。我自己更喜欢将它们存储为显式整数,以防止重命名枚举破坏数据库,但在您的情况下这不是必需的。
enum CarType {
Unknown
SportCar,
Suv,
Hatchback
}
然后您需要为您的枚举编写并注册一个自定义反序列化器,以便像这样实现对“未知”的回退。它会尝试将您的数据库值解析为枚举,如果无法解析则回退到默认值(未知)。
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);
}
}
将自定义序列化程序注册为:
BsonClassMap.RegisterClassMap<ClassThatHoldsTheProperty>(ms =>
{
ms.AutoMap();
ms.GetMemberMap(i => i.CarTypeProperty)
.SetSerializer(new CustomEnumSerializer<CarType>());
});