在两列上创建约束以支持特定规则

Posted

技术标签:

【中文标题】在两列上创建约束以支持特定规则【英文标题】:Creating a constraint on two columns to support specific rule 【发布时间】:2018-08-24 14:23:27 【问题描述】:

我有一个存储设备详细信息的表。为简单起见,这些列是:

Id (Primary Key)
Name (varchar)
StatusId (Foreign Key to Status table).

Status 表有两列:

Id (Primary Key)
State (varchar)

还有两行:

[Id | State]
  1 | Active
  2 | Inactive

我想允许设备表中的多个设备具有相同的名称,但在任何时候只有其中一个可以处于活动状态。

也就是说,在Devices表中应该是允许的:

[Id | Name      | StatusId]
 10 | Mobile001 | 1
 11 | Mobile001 | 2
 12 | Mobile001 | 2
 20 | Tablet001 | 1
 21 | Tablet002 | 2
 22 | Tablet002 | 1
 23 | Tablet003 | 2

但这不应该被允许:

[Id | Name      | StatusId]
 10 | Mobile001 | 1    <-- wrong
 11 | Mobile001 | 1    <-- wrong
 12 | Mobile001 | 2    
 20 | Tablet001 | 1
 21 | Tablet002 | 1    <-- wrong
 22 | Tablet002 | 1    <-- wrong
 23 | Tablet003 | 2    

有没有办法在 T-SQL 中创建一个约束来拒绝违反此规则的插入和更新?有没有办法在 EF 代码中首先使用 EntityTypeConfigurations 和 Fluent API,可能通过 IndexAnnotation 或 IndexAttributes 来实现?

谢谢。

【问题讨论】:

使用过滤的唯一索引。 【参考方案1】:

正如@ZoharPeled 刚刚评论的那样,一种方法是使用过滤的唯一索引。

由于您只能使用一个特定名称的活动设备,因此可以如下实现:

USE Sandbox;
GO
--Create sample table
CREATE TABLE Device (ID int IDENTITY(1,1),
                     [name] varchar(10),
                     [StatusID] int);
--Unique Filtered Index
CREATE UNIQUE INDEX ActiveDevice ON Device ([name], [StatusID]) WHERE StatusID = 1;
GO

INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 0); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile2', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Fails
GO
UPDATE Device
SET StatusID = 1
WHERE ID = 2; --Also fails
GO
SELECT *
FROM Device;
GO
DROP TABLE Device;

任何问题,请尽管提问。

【讨论】:

【参考方案2】:

在 EF CF 中,您可以通过设置唯一索引(如 this answer 中所述)来实现。

modelBuilder.Entity<Device>()
    .HasIndex(d => new  d.Name, d.StatusId )
    .IsUnique();

【讨论】:

以上是关于在两列上创建约束以支持特定规则的主要内容,如果未能解决你的问题,请参考以下文章

在两列上创建索引以检查日期是不是介于这两个列之间

模式构建器 laravel 迁移在两列上是唯一的

SQLalchemy:在两列上连接一个表

MySQL在两列上左连接

在两列上检查唯一性的有效方法?

在 JOIN 中没有同时在两列上使用杜松子酒