You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:54:56