在数据库中存储枚举的最佳方法
使用 C# 和 Visual Studio 以及 MySQL 数据连接器在数据库中存储枚举的最佳方法是什么。
我将创建一个包含 100 多个枚举的新项目,其中大部分必须存储在数据库中。为每个转换器创建转换器将是一个漫长的过程,因此我想知道 Visual Studio 或某人是否有任何我没有听说过的方法。
What is the best method of storing an Enum in a Database using C# And Visual Studio and MySQL Data Connector.
I am going to be creating a new project with over 100 Enums, and majority of them will have to be stored in the database. Creating converters for each one would be a long winded process therefore I'm wondering if visual studio or someone has any methods for this that I haven't heard off.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
效果就像一个魅力!无需在代码中转换 (int)Enum 或 (Enum)int。只需首先使用 enum 和 ef 代码将为您保存 int 。 ps:“[EnumDataType(typeof(PhoneTypes))]”属性不是必需的,如果您需要附加功能,只需额外添加即可。
或者你可以这样做:
Works like a charm! No need to convert (int)Enum or (Enum)int in code. Just use the enum and ef code first will save the int for you. p.s.: "[EnumDataType(typeof(PhoneTypes))]" attribute is not required, just an extra if you want additional functionality.
Alternatively you can do:
我们将其存储为 int 或 long,然后我们可以来回转换它们。可能不是最强大的解决方案,但这就是我们所做的。
我们正在使用类型化数据集,因此,例如:
We store ours as ints or longs and then we can just cast 'em back and forth. Probably not the most robust solution, but that what we do.
we are using typed DataSets, so, for example:
如果您需要将枚举字段的字符串值存储在数据库中,最好如下所示。
例如,如果您使用不支持枚举字段的 SQLite,则可能需要它。
If you need store in DB string values of enum field, better do like show below.
For example, it can be needed if you are using SQLite, which don`t support enum fields.
如果您想要存储所有枚举值,您可以尝试使用下表来存储枚举及其成员,以及添加这些值的代码片段。但是,我只会在安装时执行此操作,因为在重新编译之前这些值永远不会改变!
数据库表:
C# 代码片段:
If you want a store of all of your enums values, you can try the below tables to store enums and their members, and the code snippet to add those values. I'd only do this at install time, however, since those values will never change until you recompile!
DB Table:
C# Snippet:
最后,您将需要一种很好的方法来处理重复的编码任务,例如枚举转换器。您可以使用代码生成器,例如 MyGeneration 或 CodeSmith 等等,或者可能是一个 ORM 映射器,例如 nHibernate< /a> 为您处理一切。
至于结构......对于数百个枚举,我首先考虑尝试将数据组织到一个表中,该表可能看起来像这样:(伪sql)
这将允许您将枚举信息存储在单个表中。 EnumType 也可以是定义不同枚举的表的外键。
您的 biz 对象将通过 EnumId 链接到该表。枚举类型仅用于 UI 中的组织和过滤。当然,使用所有这些取决于您的代码结构和问题域。
顺便说一句,在这种情况下,您可能希望在 EnumType 上设置聚集索引,而不是保留在 PKey 上创建的默认集群 idx。
In the end you will need a great way to deal with repetitious coding tasks such as enum converters. You can use a code generator such as MyGeneration or CodeSmith among many others or perhaps an ORM mapper like nHibernate to handle everything for you.
As for the structure... with hundreds of enums I would first consider trying to organize the data into a single table that might look something like this: (pseudo sql)
that would allow you to store your enum info in a single table. EnumType could also be a foreign key to a table that defines the different enums.
Your biz objects would be linked to this table via EnumId. The enum type is there only for organization and filtering in the UI. Utilizing all of this of course depends on your code structure and problem domain.
Btw, in this scenario you would want to set a clustered index on EnumType rather than leaving the default cluster idx that is created on the PKey.
有些事情你应该考虑。
枚举列是否将直接由其他应用程序(例如报告)使用。这将限制枚举以整数格式存储的可能性,因为除非报告具有自定义逻辑,否则该值出现在报告中时没有任何意义。
您的应用程序的 i18n 需求是什么?如果它仅支持一种语言,您可以将枚举保存为文本并创建一个辅助方法来从描述字符串进行转换。您可以使用
[DescriptionAttribute]
来实现此目的,并且可以通过搜索 SO 找到转换方法。另一方面,如果您需要支持多种语言和外部应用程序对数据的访问,您可以开始考虑枚举是否真的是答案。如果场景更复杂,可以考虑其他选项,例如查找表。
当枚举自我包含在代码中时,它们是非常好的......当它们跨越边界时,事情往往会变得有点混乱。
更新:
您可以使用
Enum.ToObject
方法从整数进行转换。这意味着您在转换时知道枚举的类型。如果您想让它完全通用,您需要将枚举的类型与其值一起存储在数据库中。您可以创建数据字典支持表来告诉您哪些列是枚举以及它们的类型。Some things you should take in consideration.
Is the enumeration column going to be used directly by other applications like for example reports. This will limit the possibility of the enumeration being stored in it's integer format because that value will have no meaning when present in a report unless the reports have custom logic.
What are the i18n needs for your application? If it only supports one language you can save the enumeration as text and create a helper method to convert from a description string. You can use
[DescriptionAttribute]
for this and methods for the conversion can probably be found by searching SO.If on the other hand you have the need to support multiple language and external application access to your data you can start considering if enumeration are really the answer. Other option like lookup tables can be considered if the scenario is more complex.
Enumerations are excellent when they are self contained in code... when they cross that border, things tend to get a bit messy.
Update:
You can convert from an integer using
Enum.ToObject
method. This implies that you know the type of the enumeration when converting. If you want to make it completely generic you need to store the type of the enumeration alongside it's value in the database. You could create data dictionary support tables to tell you which columns are enumerations and what type are them.如果你想存储整数,你不需要做任何事情。只需在 EF 中映射您的财产即可。
如果你想将它们存储为字符串,请使用转换器。
Int(db类型为smallint):
String(db类型为varchar(50)):
如果您想保存db数据使用情况,请使用smallint作为db中的列。但是数据不是人类可读的,您应该为每个枚举项设置一个索引,并且永远不要弄乱它们:
如果您想让数据库中的数据更具可读性,您可以将它们保存为字符串(例如 varchar(50))。您不必担心索引,只需在更改枚举名称时更新数据库中的字符串即可。缺点:列大小会使数据使用成本更高。这意味着如果您的表的行数在 1,000,000 以内,则可能会对数据库大小和性能产生影响。
另外,作为解决方案,您可以使用短枚举名称:
或者使用您自己的转换器使数据库中的名称更短:
可以在此处找到更多信息:
EF5:https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/data-类型/枚举
EF6:https://learn .microsoft.com/en-us/ef/core/modeling/value-conversions
You don't need to do anything if you want to store ints. Just map your property in EF.
If you want to store them as strings use converter.
Int (db type is smallint):
String (db type is varchar(50)):
If you want to save your db data usage use smallint as a column in db. But data won't be human readable and you should set an index against every enum item and never mess with them:
If you want to make data in db more readable you can save them as strings (e.g. varchar(50)). You don't have to worry about indexes and you just need update strings in db when you change enum names. Cons: column size gets data usage more expensive. It means if you got a table within 1,000,000 rows it might have an impact on db size and performance.
Also as a solution you can use short enum names:
Or use your own converter to make names in db shorter:
More info can be found here:
EF5: https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/data-types/enums
EF6: https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions
我不确定它是否是最灵活的,但您可以简单地存储它们的字符串版本。它当然是可读的,但可能难以维护。枚举与字符串之间的转换非常容易:
I'm not sure if it is the most flexible, but you could simply store the string versions of them. It is certainly readable, but maybe difficult to maintain. Enums convert from strings and back pretty easily:
可以通过为每个枚举创建一致的表来使用数据库优先方法,其中 Id 列名称与表名称匹配。在数据库中使用枚举值来支持外键约束和视图中的友好列是有利的。目前,我们支持分散在众多版本数据库中的约 100 种枚举类型。
对于代码优先首选项,可以反转下面所示的 T4 策略来写入数据库。
每个表都可以使用 T4 模板 (*.tt) 脚本导入到 C# 中。
内容始终是同一行:<#@ include
文件=“..\EnumGenerator.ttinclude”#>
“运行自定义工具”(我们还没有自动更新)。它将向项目添加/更新 .cs 文件:
最后是有点粗糙的 T4 脚本(通过众多解决方法进行简化)。它需要根据您的环境进行定制。调试标志可以将消息输出到 C# 中。右键单击 .tt 文件时还有一个“调试 T4 模板”选项。
EnumGenerator.ttinclude:
希望实体框架有一天能够支持这些答案的组合,以在记录和值的数据库镜像中提供 C# 枚举强类型。
A DB first approach can be used by creating a consistent table for each enum where the Id column name matches table name. It's advantageous to have enum values available within the database to support foreign key constraints and friendly columns in views. We are currently supporting ~100 enum types scattered throughout numerous versioned databases.
For a Code-First preference, the T4 strategy shown below could probably be reversed to write to the database.
Each table can be imported into C# using a T4 template (*.tt) script.
contents are always the same single line: <#@ include
file="..\EnumGenerator.ttinclude" #>
"Run Custom Tool" (we don't have auto update yet). It will add/update a .cs file to the project:
And finally, the somewhat gnarly T4 script (simplified from numerous workarounds). It will need to be customized to your environment. A debug flag can output messages into the C#. There is also a "Debug T4 Template" option when right clicking the .tt file.
EnumGenerator.ttinclude:
Hopefully the entity framework will someday support a combination of these answers to offer the C# enum strong typing within records and database mirroring of values.
如果您使用的是 EntityFrameworkCore。 (我的版本是5.0.10),而不是像这样直接使用Fluent API:(这将在数据库中保存Home/Other。在数据库中创建
Type
列作为varchar/nvarchar)在您的上下文文件中,您继承 DbContext
我的实体:
我的枚举:
额外注释,不是强制性的,与上面的示例无关: 在我的这个场景中,这不是必需的。但只要需要,您始终可以在数据库级别创建约束。
If you are using EntityFrameworkCore. (mine version is 5.0.10), than directly use Fluent API like this: (This will save Home/Other in DB. create
Type
columns as varchar/nvarchar in your database)In your Context file, where you are inheriting the DbContext
My Entity:
My Enum:
Extra Notes, not mandatory and not related to above sample: This is not required in my this scenario. But you can always create a constraint as well at DB level, wherever required.
为什么不尝试将枚举与数据库完全分离呢?我发现这篇文章在处理类似的事情时是一个很好的参考:
http://stevesmithblog.com/blog/reducing-sql-lookup-tables-and-function-properties-in-nhibernate/
无论您使用什么数据库,其中的想法都应该适用。例如,在 MySQL 中,您可以使用“enum”数据类型来强制遵守编码枚举:
http://dev.mysql.com/doc/refman/5.0/en/enum.html
Why not try separating the enums altogether from the DB? I found this article to be a great reference while working on something similar:
http://stevesmithblog.com/blog/reducing-sql-lookup-tables-and-function-properties-in-nhibernate/
The ideas in it should apply regardless of what DB you use. For example, in MySQL you can use the "enum" data type to enforce compliance with your coded enums:
http://dev.mysql.com/doc/refman/5.0/en/enum.html