如何在MongoDB中以小写或自定义格式存储C#枚举值?
这个问题我之前也碰到过——MongoDB的C#驱动并不会自动识别Json.NET的[JsonConverter]或者[EnumMember]属性,因为它有一套自己的BSON序列化体系,你之前加的[BsonRepresentation(BsonType.String)]只是告诉驱动把枚举存成字符串,但默认还是用枚举的原始名称,不会去读EnumMember的自定义值。
下面给你两种可行的解决方法,按需选择:
方法一:自定义枚举序列化器(推荐,精准控制)
写一个自定义的BSON序列化器,专门处理带有[EnumMember]属性的枚举,序列化时取属性指定的值,反序列化时也能正确映射回来。
首先创建序列化器类:
using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using System.Reflection; using System.Runtime.Serialization; public class EnumMemberSerializer<TEnum> : EnumSerializer<TEnum> where TEnum : struct, Enum { public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TEnum value) { var enumType = typeof(TEnum); var memberInfo = enumType.GetMember(value.ToString()).FirstOrDefault(); // 优先取EnumMember的Value,没有的话转小写 var serializedValue = memberInfo?.GetCustomAttribute<EnumMemberAttribute>()?.Value ?? value.ToString().ToLowerInvariant(); context.Writer.WriteString(serializedValue); } public override TEnum Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var stringValue = context.Reader.ReadString(); var enumType = typeof(TEnum); // 先匹配EnumMember的Value foreach (var member in enumType.GetMembers()) { var enumMemberAttr = member.GetCustomAttribute<EnumMemberAttribute>(); if (enumMemberAttr?.Value == stringValue) { return (TEnum)Enum.Parse(enumType, member.Name); } } // 如果没匹配到,尝试忽略大小写匹配枚举名称 return (TEnum)Enum.Parse(enumType, stringValue, ignoreCase: true); } }
然后把这个序列化器应用到你的枚举或者属性上:
方式1:直接在枚举类上标注
[BsonSerializer(typeof(EnumMemberSerializer<MyEnum>))] // JsonConverter保留给Json.NET用,不影响MongoDB [JsonConverter(typeof(StringEnumConverter))] enum MyEnum { [EnumMember(Value = "first_value")] FirstValue, [EnumMember(Value = "second_value")] SecondValue }
方式2:在类的属性上标注
class MyClass { // 其他属性... [BsonSerializer(typeof(EnumMemberSerializer<MyEnum>))] public MyEnum EnumValue { get; set; } // 其他属性... }
方式3:全局注册,所有枚举生效
如果你的项目里有很多枚举都需要这个规则,可以全局注册序列化器,不用逐个标注:
// 针对单个枚举 BsonSerializer.RegisterSerializer(typeof(MyEnum), new EnumMemberSerializer<MyEnum>()); // 或者针对所有枚举(需要自定义Convention) var conventionPack = new ConventionPack(); // 确保所有枚举都以字符串形式存储 conventionPack.Add(new EnumRepresentationConvention(BsonType.String)); // 给所有枚举应用自定义序列化器 conventionPack.Add(new EnumSerializerConvention(type => Activator.CreateInstance(typeof(EnumMemberSerializer<>).MakeGenericType(type)) as IBsonSerializer)); ConventionRegistry.Register("EnumMemberConventions", conventionPack, t => t.IsEnum);
方法二:仅需小写格式的简化方案
如果不需要EnumMember的自定义值,只是想把枚举名称转小写存储,可以用更简单的序列化器:
public class LowercaseEnumSerializer<TEnum> : EnumSerializer<TEnum> where TEnum : struct, Enum { public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TEnum value) { context.Writer.WriteString(value.ToString().ToLowerInvariant()); } public override TEnum Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var stringValue = context.Reader.ReadString(); return (TEnum)Enum.Parse(typeof(TEnum), stringValue, ignoreCase: true); } }
应用方式和上面一样,替换掉序列化器类型即可。
最后再强调一下:你之前加的[JsonConverter]只对Json.NET的序列化生效(比如Web API返回JSON的时候),MongoDB驱动完全不识别它,所以必须用MongoDB自己的BSON序列化器来实现需求。
内容的提问来源于stack exchange,提问作者Jimi
相关产品推荐
相关产品推荐

