如何将大型标志枚举存储到 SQL 数据库中的单个列?

res*_*tel 3 c# sql enums enum-flags entity-framework-core

我有这个枚举:

[Flags]
public enum Actions 
{
    None = 0,
    MoveUp = 1,
    MoveDown = 2,
    MoveRight = 3,
    MoveLeft = 4
}
Run Code Online (Sandbox Code Playgroud)

我想要这样的表的列:

Id | UserId | Actions
.. | ..     | ..
Run Code Online (Sandbox Code Playgroud)

我对如何存储枚举感到困惑,因为用户可以有多个操作,并且我不想使用另一张表来存储操作。我有超过 50 个操作,这就是我使用该Flags属性的原因。

actionssUser = Actions.MoveUp | Actions.MoveRight | ....... 
Run Code Online (Sandbox Code Playgroud)

Jer*_*ney 6

首先,重要的是要注意您的标志枚举未正确配置,并且几乎肯定不会按照您期望的方式运行。如文档中所述

\n
\n

定义 2 的幂的枚举常量,即 1、2、4、8 等。这意味着组合枚举常量中的各个标志不会重叠。

\n
\n

最后一句话在这里特别重要,稍后您就会看到。

\n

例子

\n

让我们使用您的示例将其付诸实践。您的枚举应该如下所示:

\n
[Flags]\npublic enum Actions \n{\n    None            = 0,\n    MoveUp          = 1,\n    MoveDown        = 2,\n    MoveRight       = 4,\n    MoveLeft        = 8\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在,假设您将枚举值设置为包含MoveUpMoveRight标志:

\n
var actions = Actions.MoveUp | Actions.MoveRight;\n
Run Code Online (Sandbox Code Playgroud)\n

您现在可以使用简单的转换将其转换为整数:

\n
var actionsValue = (int)actions;\n
Run Code Online (Sandbox Code Playgroud)\n

在此示例中,将返回 5。此时,您可以简单地将该值作为标准存储在 SQL Server 中,例如TINYINT(假设您有八个或更少的选项),如@Charlieface 在注释中指出的那样。

\n

或者,更好的是,您可以将其转换为 a byte,并将其存储为BINARY(4)列\xe2\x80\x94 或BINARY(50)带有完整枚举\xe2\x80\x94的 a ,如@meysam-asadi建议的那样:

\n
var actionsValue = (byte)actions;\n
Run Code Online (Sandbox Code Playgroud)\n

解释

\n

如果您查看上面的值,当您使用 2 的幂时,唯一可能返回 5 的组合是 1 ( MoveUp) 和 4 (MoveRight )。

\n

如果您了解二进制,这会更加直观,因为您的位数组将如下所示:

\n
0101\n
Run Code Online (Sandbox Code Playgroud)\n

或者,从右到左:

\n
Bit    Int    Label\n1      1      MoveUp\n0      2      MoveDown\n1      4      MoveRight\n0      8      MoveLeft\n
Run Code Online (Sandbox Code Playgroud)\n

基本上,每个后续的 2 的幂都会将下一个数字从 0 翻转到 1,将该选项标记为已标记。

\n

复活你的旗帜

\n

在回程中,过程看起来非常相似,只是相反。因此,当您从数据库检索值时,只需将其转换回枚举即可:

\n
0101\n
Run Code Online (Sandbox Code Playgroud)\n

(在哪里actionsValue从数据库检索到的值在哪里。)

\n

局限性

\n

这里有限制!如果您使用这种方法,您需要确保您的价值观是稳定的。如果您尝试将值注入现有枚举中,则需要相应地重新计算以前的所有记录。为了避免这种情况,您需要将任何新值添加到枚举的末尾。如果这不是可接受的限制,您最好将这些值存储在单独的列中。

\n

速记

\n

这是题外话,但由于您有超过 50 个枚举值,因此可以使用一种分配 2 的幂的简写形式,\xe2\x80\x99s 更容易计数:

\n
Bit    Int    Label\n1      1      MoveUp\n0      2      MoveDown\n1      4      MoveRight\n0      8      MoveLeft\n
Run Code Online (Sandbox Code Playgroud)\n

这比尝试将 2^50 写为 1125899906842624 更容易

\n