我觉得这个不错。首先,我真的不知道什么是触发器,现在可能很明显了。
触发器是否有利于维护数据库模式之间的向后兼容性?假设我在版本1中有一个一对多的关系。在版本2中,这已更改为多对多。是否正确实现触发器能够处理这一点,以便允许两个版本在同一数据库上运行?这是个好主意吗?
实现向后兼容性从来都不是直截了当的。假设您有(版本1):
CREATE TABLE T1 (
ID int not null primary key,
ColA varchar(10) not null
)
CREATE TABLE T2 (
ID int not null primary key,
T1ID int not null,
ColB varchar(10) not null,
constraint FK_T2_T1 FOREIGN KEY (T1ID) references T1
)
,现在,对于版本2,您希望引入:
CREATE TABLE T1_T2 (
T1ID int not null,
T2ID int not null,
constraint PK_T1_T2 PRIMARY KEY (T1,T2),
constraint FK_T1_T2_T1 FOREIGN KEY (T1ID) references T1,
constraint FK_T1_T2_T2 FOREIGN KEY (T2ID) references T2
)
而且,我从你的问题中想象,你认为T1_T2
上的活动可以维持T2
中现有的T1ID
列,以实现向后兼容性。
这当然可能发生,但是你有一大堆问题要解决:
- 如果
T1_T2
中有多行,您应该将哪个T1ID
值写入T2
? - 如果这行被删除,
T2
中的T1ID
应该发生什么-设置NULL,选择另一个值? - 如果匹配
T2ID
的所有行从T1_T2
中删除怎么办?应该删除T2
中的行吗?是否将T1ID
设置为NULL? - 如果版本1应用程序在
T2
中更新T1ID
,并且在T1_T2
中不存在行,这是一个错误还是应该插入新行? - 如果
T2
中的行没有特定的T1ID
,那么版本1应用程序可能会假设它可以从T1
中删除一行
我相信还有更多。您可以解决所有这些问题,但您永远无法完美地模拟版本1模式的100%使用的旧行为。
如果你能解决以上所有的问题,让你满意,那么是的,你可以使用触发器执行这些维护任务。正如我所说的那样,它不会是100%,所以您可能仍然需要调整版本1应用程序来解决他们的一些期望。
是的,您可以通过在旧版本的视图上使用一个INSTEAD OF触发器来插入、更新和删除。为了更清楚地说明这一点,让我们考虑以下示例:
v1:
A(id int, data varchar(30))
B(id int, a_id int, data varchar(30))
v2:
A(id int, data varchar(30))
B(id int, data varchar(30), data2 varchar(20))
AB(a_id int, b_id int)
首先创建一个视图来模拟旧版本的B表。棘手的事情是决定将哪个AB关系显示给旧的应用程序。一种选择是将bit
类型的primary_b
列添加到AB
表中。下面的视图使用了这个选项
CREATE VIEW OldB AS
SELECT B.id AS id, AB.a_id AS a_id, B.data AS data,
FROM B INNER JOIN AB ON B.id = AB.b_id
WHERE AB.primary_b = 1
接下来,您将在视图上创建触发器来处理插入和更新。
CREATE TRIGGER InsertTrigger on OldB INSTEAD OF INSERT
AS
BEGIN
INSERT INTO B (id, data) SELECT id, data FROM inserted;
UPDATE AB SET primary_b = 0 WHERE b_id IN (SELECT id FROM inserted);
INSERT INTO AB (a_id, b_id, primary_b) SELECT a_id, id, 1 FROM inserted;
END
GO
你会做一些类似的事情,而不是更新,除了你必须通过删除和添加行来管理A到B链接的变化。我还没有检查出错误的代码,但我将在接下来的一个小时左右,如果需要,发布更新。
您可能需要一些视图和触发器的组合