关系数据库中的枚举 这是关系数据库中非常基础的一门学科,但是却常常没有被很好地理解,有时实现得很差。当然,有很多方法可以做到这一点,但我只集中讨论两种情况,一种是“正确的方法”,而另一种肯定是错误的方法。
这个概念 假设我们的数据库中有表Person。人物具有属性/字段,例如名字,姓氏,生日等等。然后是一个字段,告知人的婚姻状况,让我们以相同的方式命名。婚姻状况。
现在,MaritalStatus是一个枚举。在C#中,我肯定会使用诸如Single,InRelationship,Married,Divorced之类的值进行枚举。现在出现了问题,SQL没有枚举。
错误的方法 我认为,这绝对是错误的方法。它有一个优势。当您执行简单的SELECT查询时,您将立即看到枚举的描述,而不必处理神秘的值。缺点也很多,其中之一就是数据库碎片。
考虑一下(我故意将所有索引和约束都排除在查询之外)。
CREATE TABLE [dbo].[Person] ( [Firstname] NVARCHAR(100), [Lastname] NVARCHAR(100), [Birthday] datetime, [MaritalStatus] NVARCHAR(10) )
您在表中有nvarchar(20)字段,用于告知婚姻状况。显而易见的问题是,如果创建的新值不适合20个字符,该怎么办?您必须要来改变桌子。还有其他问题,但我留给读者考虑。
正确的方法 这是我在许多项目中完成此操作的方式。该模型仍然存在一个问题,但是可以根据需要在应用程序层或使用CHECK约束进行缓解。
首先,我将创建一个命名空间表,该表告诉枚举的名称。我也将添加一行。我也将在这里编写所有索引和约束。
CREATE TABLE [CodeNamespace] ( [Id] INT IDENTITY(1, 1), [Name] NVARCHAR(100) NOT NULL, CONSTRAINT [PK_CodeNamespace] PRIMARY KEY ([Id]), CONSTRAINT [IXQ_CodeNamespace_Name] UNIQUE NONCLUSTERED ([Name]) ) GO INSERT INTO [CodeNamespace] SELECT 'MaritalStatus' GO
然后,我创建一个表,其中包含实际值以及对命名空间表的引用,以便将值分组到不同的命名空间下。我也会在这里添加几行。
CREATE TABLE [CodeValue] ( [CodeNamespaceId] INT NOT NULL, [Value] INT NOT NULL, [Description] NVARCHAR(100) NOT NULL, [OrderBy] INT, CONSTRAINT [PK_CodeValue] PRIMARY KEY CLUSTERED ([CodeNamespaceId], [Value]), CONSTRAINT [FK_CodeValue_CodeNamespace] FOREIGN KEY ([CodeNamespaceId]) REFERENCES [CodeNamespace] ([Id]) ) GO -- 1 is the 'MaritalStatus' namespace INSERT INTO [CodeValue] SELECT 1, 1, 'Single', 1 INSERT INTO [CodeValue] SELECT 1, 2, 'In relationship', 2 INSERT INTO [CodeValue] SELECT 1, 3, 'Married', 3 INSERT INTO [CodeValue] SELECT 1, 4, 'Divorced', 4 GO
现在,在CodeValue表中有四列。CodeNamespaceId告知名称空间值属于哪个名称。值告诉在Person表中使用的枚举值(我将在下面显示如何完成此操作)。说明说明该值的含义。您可以使用此列,例如,UI组合框中的列。OrderBy指示在UI中显示值时是否需要以某种方式对值进行排序。
这又是带有正确列的Person表。我将在此处添加一行以显示枚举的使用方式。
CREATE TABLE [dbo].[Person] ( [Firstname] NVARCHAR(100), [Lastname] NVARCHAR(100), [Birthday] datetime, [MaritalStatus] INT ) GO INSERT INTO [Person] SELECT 'Marko', 'Parkkola', '1977-03-04', 3 GO
现在我刚才说过,这有一个问题。MaritalStatus列与CodeValue表没有任何数据库强制关系,因此您可以在此字段中输入您喜欢的任何值。我已经在应用程序层中解决了这个问题,方法是从CodeValue表中选择所有值,然后将它们放入组合框/下拉列表中(“值”字段为值,“描述”为文本),以便最终用户不能输入任何非法值。当然,我还将在数据访问层中检查输入的值。
我在“错误的方式”部分中说过,这样做有一个好处。实际上,使用简单的视图即可在这里获得相同的好处,该视图已绑定了架构,因此您可以根据需要对其进行索引。
CREATE VIEW [dbo].[Person_v] WITH SCHEMABINDING AS SELECT p.[Firstname], p.[Lastname], p.[BirthDay], c.[Description] MaritalStatus FROM [dbo].[Person] p JOIN [dbo].[CodeValue] c ON p.[MaritalStatus] = c.[Value] JOIN [dbo].[CodeNamespace] n ON n.[Id] = c.[CodeNamespaceId] AND n.[Name] = 'MaritalStatus' GO -- Select from View SELECT * FROM [dbo].[Person_v] GO
原文链接:https://codingdict.com/