SQL:如何让 non-unique "identity column" 具有自动 SET 行为?
SQL: How to have a non-unique "identity column", with automatic SET behaviour?
想法
因此,标题可能看起来有些含糊,但这是我想要的(在 Microsoft SQL 服务器中,最新版本),用于 ASP.NET C# 应用程序:
- 具有普通主键的table,定义为“官方”标识列
- 其他一些专栏
- 一个额外的“逻辑标识”列
附加的“逻辑标识”列应具有以下属性
- 是整数类型
- 并非严格唯一(多行可以具有相同的“本地身份”)
- 强制性
- immutable(一旦设置,可能永远不会改变)。但是必须允许删除该行。
- 如果未在 INSERT 中提供,则设置为尚未使用的值
最后一点可能是最难实现的,所以这就是问题所在:
问题
当 INSERT 脚本未提供强制值时,如何强制(最好在数据库级别)强制值始终设置为唯一值?
想法
我考虑过的:
- 不可能在该列上有一个正常的“标识”,因为它在现有值中不是唯一的
- 不可能有随机值,因为它对于新值必须是唯一的
- 扩展 =SaveChanges= 方法会有问题,因为它需要查询其中的数据库
- 也许是数据库触发的功能,但我希望有更简单的解决方案
上下文
- 在某些情况下,尤其是当插入具有相同“逻辑标识”的附加行时,应用程序已经定义了“逻辑标识”,应该使用它。
- 目前,当应用程序将一个值设置为“逻辑ID”时,它将在现有值中。因此,我可以强制数据库只接受至少存在一次的插入值。当需要提供新的唯一值时,这会有所帮助。
- 但是,如果这是某种新项目,系统应该在插入时即时提供新的“本地标识”。必须确保没有为此重用现有值。
- 我将使用 Entity Framework(版本 6)作为我的 ORM。
- 如果不满足以上要求,在“Add”上抛出异常
- 如果要更改这样的值,则应在“更新”时抛出异常
一个选项是为 SEQUENCE
值分配 DEFAULT
约束。不可变的要求是最大的挑战,因为 SQL 服务器不提供指定 read-only 列的声明方式,因此需要触发器实现。
下面是示例 DDL。我不知道这种技术是否会对 EF 提出挑战。
CREATE SEQUENCE SQ_Example_Sequence
AS int START WITH 1 INCREMENT BY 1;
GO
CREATE TABLE dbo.Example(
IdentityColumn int NOT NULL IDENTITY
CONSTRAINT PK_Example PRIMARY KEY CLUSTERED
,SomeDataColumn int
,SequenceColumn int NOT NULL
CONSTRAINT DF_Example_SequenceColumn DEFAULT NEXT VALUE FOR SQ_Example_Sequence
);
GO
CREATE TRIGGER TR_Example_Update
ON dbo.Example FOR UPDATE
AS
IF EXISTS(SELECT 1
FROM inserted
JOIN deleted ON inserted.IdentityColumn = deleted.IdentityColumn
WHERE inserted.SequenceColumn <> deleted.SequenceColumn
)
BEGIN
THROW 50000, 'SequenceColumn value cannot be changed', 16;
END;
GO
想法
因此,标题可能看起来有些含糊,但这是我想要的(在 Microsoft SQL 服务器中,最新版本),用于 ASP.NET C# 应用程序:
- 具有普通主键的table,定义为“官方”标识列
- 其他一些专栏
- 一个额外的“逻辑标识”列
附加的“逻辑标识”列应具有以下属性
- 是整数类型
- 并非严格唯一(多行可以具有相同的“本地身份”)
- 强制性
- immutable(一旦设置,可能永远不会改变)。但是必须允许删除该行。
- 如果未在 INSERT 中提供,则设置为尚未使用的值
最后一点可能是最难实现的,所以这就是问题所在:
问题
当 INSERT 脚本未提供强制值时,如何强制(最好在数据库级别)强制值始终设置为唯一值?
想法
我考虑过的:
- 不可能在该列上有一个正常的“标识”,因为它在现有值中不是唯一的
- 不可能有随机值,因为它对于新值必须是唯一的
- 扩展 =SaveChanges= 方法会有问题,因为它需要查询其中的数据库
- 也许是数据库触发的功能,但我希望有更简单的解决方案
上下文
- 在某些情况下,尤其是当插入具有相同“逻辑标识”的附加行时,应用程序已经定义了“逻辑标识”,应该使用它。
- 目前,当应用程序将一个值设置为“逻辑ID”时,它将在现有值中。因此,我可以强制数据库只接受至少存在一次的插入值。当需要提供新的唯一值时,这会有所帮助。
- 但是,如果这是某种新项目,系统应该在插入时即时提供新的“本地标识”。必须确保没有为此重用现有值。
- 我将使用 Entity Framework(版本 6)作为我的 ORM。
- 如果不满足以上要求,在“Add”上抛出异常
- 如果要更改这样的值,则应在“更新”时抛出异常
一个选项是为 SEQUENCE
值分配 DEFAULT
约束。不可变的要求是最大的挑战,因为 SQL 服务器不提供指定 read-only 列的声明方式,因此需要触发器实现。
下面是示例 DDL。我不知道这种技术是否会对 EF 提出挑战。
CREATE SEQUENCE SQ_Example_Sequence
AS int START WITH 1 INCREMENT BY 1;
GO
CREATE TABLE dbo.Example(
IdentityColumn int NOT NULL IDENTITY
CONSTRAINT PK_Example PRIMARY KEY CLUSTERED
,SomeDataColumn int
,SequenceColumn int NOT NULL
CONSTRAINT DF_Example_SequenceColumn DEFAULT NEXT VALUE FOR SQ_Example_Sequence
);
GO
CREATE TRIGGER TR_Example_Update
ON dbo.Example FOR UPDATE
AS
IF EXISTS(SELECT 1
FROM inserted
JOIN deleted ON inserted.IdentityColumn = deleted.IdentityColumn
WHERE inserted.SequenceColumn <> deleted.SequenceColumn
)
BEGIN
THROW 50000, 'SequenceColumn value cannot be changed', 16;
END;
GO