MongoDB驱动过滤器枚举序列化问题:Type字段查询失败
问题描述
我在对Type字段(枚举类型CloudFileTypes)进行查询时遇到了问题:用LINQ或MongoDB驱动过滤器查询时,驱动会把Type识别为数字,导致匹配不上数据库里存储的字符串值;但单独查询某个文件并访问Type字段时,却能正常返回枚举成员。
问题代码片段
public CloudFile GetRoot(User user) { var builder = Builders<CloudFile>.Filter; var query = builder.Eq(e => e.Type, CloudFileTypes.Root); var root = _fileCollection.Find(query).First(); return root.First(); }
CloudFile模型
public class CloudFile { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("name")] public string Name { get; set; } [JsonConverter(typeof(JsonStringEnumConverter))] [BsonElement("type")] public CloudFileTypes Type { get; set; } [BsonElement("size")] public int Size { get; set; } [BsonElement("path")] public string Path { get; set; } [BsonRepresentation(BsonType.ObjectId)] [BsonElement("user")] public string User { get; set; } [BsonRepresentation(BsonType.ObjectId)] [BsonElement("parent")] public string Parent { get; set; } [BsonRepresentation(BsonType.ObjectId)] [BsonElement("childs")] public string[] Childs { get; set; } } public enum CloudFileTypes { [EnumMember(Value = "root")] Root, [EnumMember(Value = "folder")] Folder, [EnumMember(Value = "file")] File, }
编辑补充:我已经做了自定义JsonConverter用来把枚举序列化后返回给客户端,用了扩展方法实现:
public class EnumStringConverter<TEnum> : JsonConverter where TEnum: struct, Enum { public override bool CanConvert(Type objectType) { return objectType == typeof(CloudFileTypes); } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value is not TEnum @enum) return; if (!Attribute.IsDefined(@enum.GetType().GetMember(@enum.ToString()).FirstOrDefault(), typeof(EnumMemberAttribute))) writer.WriteValue(@enum.ToString()); writer.WriteValue(EnumExtensions.GetEnumMemberValue(@enum)); } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); var str = jo.ToString(); var obj = EnumExtensions.EnumMemberValueToEnum<CloudFileTypes>(str); return obj; } }
现在就差解决查询时驱动把枚举转成数字的问题,该怎么处理?
解决方案
核心问题是MongoDB驱动默认会把枚举序列化为数字,但你的数据库存的是EnumMember特性指定的字符串值,驱动查询时没识别这个特性。下面是几种解决方法:
方法1:给字段添加MongoDB序列化特性
直接在CloudFile的Type字段上添加两个MongoDB特性,让驱动处理枚举时用字符串值:
[JsonConverter(typeof(JsonStringEnumConverter))] [BsonElement("type")] [BsonRepresentation(BsonType.String)] [BsonSerializer(typeof(EnumMemberSerializer<CloudFileTypes>))] public CloudFileTypes Type { get; set; }
BsonRepresentation(BsonType.String):告诉驱动把这个枚举字段当作字符串类型处理EnumMemberSerializer<CloudFileTypes>:让驱动读取EnumMember特性里的Value值,作为存储和查询的字符串内容
方法2:全局配置枚举序列化规则
如果项目里有多个枚举字段需要统一处理,可以在初始化MongoDB客户端时全局配置:
var settings = MongoClientSettings.FromConnectionString("你的数据库连接字符串"); settings.LinqProvider = LinqProvider.V3; // 注册EnumMemberSerializer作为CloudFileTypes的默认序列化器 BsonSerializer.RegisterSerializer(new EnumMemberSerializer<CloudFileTypes>()); var client = new MongoClient(settings);
这样所有CloudFileTypes类型的字段,都会自动用EnumMember的字符串值进行序列化和查询。
临时 workaround(不推荐长期用)
如果暂时不想改特性或全局配置,也可以在查询时手动把枚举转成对应的字符串值:
// 先通过扩展方法拿到EnumMember的Value var rootTypeStr = EnumExtensions.GetEnumMemberValue(CloudFileTypes.Root); // 直接用字符串查询type字段 var query = builder.Eq("type", rootTypeStr); var root = _fileCollection.Find(query).First();
这种方法需要手动处理每个枚举值,代码冗余,只适合临时应急,优先推荐前两种方法。
内容的提问来源于stack exchange,提问作者Huhnak
相关产品推荐
相关产品推荐

