在 MongoDB 中将枚举存储为字符串
有没有办法将枚举存储为字符串名称而不是序数值?
示例:
假设我有这个枚举:
public enum Gender
{
Female,
Male
}
现在,如果某个虚构的用户存在,
...
Gender gender = Gender.Male;
...
它将以 { ... "Gender" : 1 ... } 的形式存储在 MongoDb 数据库中,
但我更喜欢这样的 { .. . “性别” : “男” ... }
这可能吗?自定义映射、反射技巧等等。
我的背景:我在 POCO 上使用强类型集合(嗯,我标记 AR 并偶尔使用多态性)。我有一个工作单元形式的薄数据访问抽象层。所以我不会序列化/反序列化每个对象,但我可以(并且确实)定义一些 ClassMap。我使用官方 MongoDb 驱动程序 + Fluent-mongodb。
Is there a way to store Enums as string names rather than ordinal values?
Example:
Imagine I've got this enum:
public enum Gender
{
Female,
Male
}
Now if some imaginary User exists with
...
Gender gender = Gender.Male;
...
it'll be stored in MongoDb database as { ... "Gender" : 1 ... }
but i'd prefer something like this { ... "Gender" : "Male" ... }
Is this possible? Custom mapping, reflection tricks, whatever.
My context: I use strongly typed collections over POCO (well, I mark ARs and use polymorphism occasionally). I've got a thin data access abstraction layer in a form of Unit Of Work. So I'm not serializing/deserializing each object but I can (and do) define some ClassMaps. I use official MongoDb driver + fluent-mongodb.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
MongoDB .NET 驱动程序允许您应用约定来确定确定的程度处理 CLR 类型和数据库元素之间的映射。
如果您希望将此应用于所有枚举,则只需为每个 AppDomain 设置一次约定(通常在启动应用程序时),而不是向所有类型添加属性或手动映射每种类型:
The MongoDB .NET Driver lets you apply conventions to determine how certain mappings between CLR types and database elements are handled.
If you want this to apply to all your enums, you only have to set up conventions once per AppDomain (usually when starting your application), as opposed to adding attributes to all your types or manually map every type:
您可以为包含枚举的类自定义类映射,并指定该成员由字符串表示。这将处理枚举的序列化和反序列化。
我仍在寻找一种方法来指定枚举全局表示为字符串,但这是我当前正在使用的方法。
You can customize the class map for the class that contains the enum and specify that the member be represented by a string. This will handle both the serialization and deserialization of the enum.
I am still looking for a way to specify that enums be globally represented as strings, but this is the method that I am currently using.
我发现仅应用 Ricardo Rodriguez' 答案 在某些情况下不足以正确序列化枚举值以字符串到 MongoDb 中:
如果您的数据结构涉及将枚举值装箱到对象中,则 MongoDb 序列化将不会使用集合
EnumRepresentationConvention
对其进行序列化。事实上,如果您查看 MongoDb 驱动程序 ObjectSerializer,它将解析装箱值的
TypeCode
(Int32
用于枚举值),并使用该类型将枚举值存储在数据库中。因此装箱的枚举值最终被序列化为int
值。反序列化时它们也将保留为int
值。要更改此设置,可以编写一个自定义
ObjectSerializer
,如果装箱值是枚举,它将强制设置EnumRepresentationConvention
。像这样的事情:然后将自定义序列化器设置为用于序列化对象的序列化器:
这样做将确保装箱的枚举值将像未装箱的枚举值一样存储为字符串。
但请记住,反序列化文档时,装箱的值将保留为字符串。它不会被转换回原始枚举值。如果您需要将字符串转换回原始枚举值,则可能需要在文档中添加区分字段,以便序列化程序可以知道要反序列化的枚举类型。
一种方法是存储一个 bson 文档而不仅仅是一个字符串,其中将使用区分字段 (
_t
) 和值字段 (_v
)存储枚举类型及其字符串值。I have found that just applying Ricardo Rodriguez' answer is not sufficient in some cases to properly serialize enum values to string into MongoDb:
If your data structure involves enum values being boxed into objects, the MongoDb serialization will not use the set
EnumRepresentationConvention
to serialize it.Indeed, if you look at the implementation of MongoDb driver's ObjectSerializer, it will resolve the
TypeCode
of the boxed value (Int32
for enum values), and use that type to store your enum value in the database. So boxed enum values end up being serialized asint
values. They will remain asint
values when being deserialized as well.To change this, it's possible to write a custom
ObjectSerializer
that will enforce the setEnumRepresentationConvention
if the boxed value is an enum. Something like this:and then set the custom serializer as the one to use for serializing objects:
Doing this will ensure boxed enum values will be stored as strings just like the unboxed ones.
Keep in mind however that when deserializing your document, the boxed value will remain a string. It will not be converted back to the original enum value. If you need to convert the string back to the original enum value, a discrimination field will likely have to be added in your document so the serializer can know what is the enum type to desrialize into.
One way to do it would be to store a bson document instead of just a string, into which the discrimination field (
_t
) and a value field (_v
) would be used to store the enum type and its string value.使用驱动程序 2.x,我使用 特定序列化器:
With driver 2.x I solved using a specific serializer:
使用 MemberSerializationOptionsConvention 定义有关如何保存枚举的约定。
Use MemberSerializationOptionsConvention to define a convention on how an enum will be saved.
如果您使用 .NET Core 3.1 及更高版本,请使用 Microsoft 最新的超快速 Json 序列化器/反序列化器 System.Text.Json (https://www.nuget.org/packages/System.Text.Json)。
请参阅 https://medium.com/@ 的指标比较samichkhachkhi/system-text-json-vs-newtonsoft-json-d01935068143
If you are using .NET Core 3.1 and above, use the latest ultra-fast Json Serializer/Deserializer from Microsoft, System.Text.Json (https://www.nuget.org/packages/System.Text.Json).
See the metrics comparison at https://medium.com/@samichkhachkhi/system-text-json-vs-newtonsoft-json-d01935068143
此处发布的答案适用于
TEnum
和TEnum[]
,但不适用于Dictionary
。您可以在使用代码初始化序列化器时实现此目的,但是我想通过属性来实现此目的。我创建了一个灵活的 DictionarySerializer,可以使用键和值的序列化器进行配置。像这样的用法,其中键和值都是枚举类型,但可以是序列化器的任意组合:
The answers posted here work well for
TEnum
andTEnum[]
, however won't work withDictionary<TEnum, object>
. You could achieve this when initializing serializer using code, however I wanted to do this through attributes. I've created a flexibleDictionarySerializer
that can be configured with a serializer for the key and value.Usage like this, where both key and value are enum types, but could be any combination of serializers:
.NET 7.0
在 @sboisse 非常好的答案上进行改进,我找到了一种满足我所有用例的方法。
通用枚举序列化程序
注册程序集中的每个枚举
注意:
.NET 7.0
Improving on @sboisse very good answer, I've found a way that satisfies all of my usecases.
Generic Enum Serializer
Registering every enum in assembly
Notes: