SQL 服务器触发器 - 如果列 IsLocked BIT 为真,则阻止行更新
SQL Server Trigger - Prevent row update if column IsLocked BIT is true
SQL 服务器 2016 由 ASP.NET 4.6.2 MVC Web 应用程序访问
我有 table "Building",一个建筑可以有多个 "Components"。例如,Building1 有 Component1 和 Component2 ... etc
有人要求我能够锁定建筑物。锁定意味着无法再修改组件 (CREATE/UPDATE/DELETE)。好吧,正如您想象的那样,这是一个巨大的应用程序,一个组件可以在 100 多个地方进行修改。甚至没有人能回答这个问题,"Where all do I need to lock?"。
我的想法是锁定所有我能想到的地方,然后作为安全网创建一个 SQL 触发器,如果组件 table "IsLocked BIT" 上的列是真的。目前,我知道组件是否被锁定的唯一方法是 IsLocked 列是否等于 true。
所以,我说了这么多。如果正在修改的行的列 IsLocked = 1,我如何创建一个 SQL 服务器触发器来防止一行数据被修改?
编辑 1
在我看来,这不是重复的。使用 Instead of Delete 或 Instead of... 对我不起作用。如果我执行而不是...,那么在其中我将需要提供提交逻辑。我不想提供提交逻辑。我只想 运行 在插入、更新、删除之前进行检查。
编辑 2 - 而不是 Update/Delete 是最佳选择
如果不是...是我的最佳选择,那么有人可以使用 update/delete 来重写我的内容吗?我不知道该怎么做。请记住,请求将来自网络应用程序。我不知道他们是在更新一列还是整个实体,或者他们将传递什么。我知道我写的方式是它会捕获任何插入/update/delete 并在锁定时阻止它。如果有更好的方法请写出来并说明为什么更好。
这是我想出的解决方案:
ALTER TRIGGER [dbo].[PreventLockedModification]
ON [dbo].[Component]
FOR INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
--DETERMINE INSERT(I) UPDATE(U) OR DELETE(D)
----------------------------------------------------------------------------------------------------
DECLARE @action as char(1);
SET @action = 'I'; -- Set Action to Insert by default.
IF EXISTS(SELECT * FROM DELETED)
BEGIN
SET @action =
CASE
WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END
END
----------------------------------------------------------------------------------------------------
DECLARE @ErrorMsg nvarchar(100) = 'This row is locked and cannot be updated';
DECLARE @IsLocked bit;
DECLARE @BuildingId bigint;
DECLARE @UnitId bigint;
DECLARE @IsComplete_Building bit;
DECLARE @IsComplete_Unit bit;
----------------------------------------------------------------------------------------------------
IF @action = 'U' or @action = 'D'
BEGIN
SELECT @IsLocked = IsLocked FROM deleted;
IF @IsLocked = 1
BEGIN
RAISERROR (@ErrorMsg, 16, 1);
ROLLBACK TRANSACTION
END
END
----------------------------------------------------------------------------------------------------
ELSE IF @action = 'I'
BEGIN
SELECT @BuildingId = BuildingId FROM inserted;
SELECT @UnitId = UnitId FROM inserted;
SELECT @IsComplete_Building = IsComplete FROM Building WHERE BuildingId = @BuildingId
SELECT @IsComplete_Unit = IsComplete FROM Unit WHERE UnitId = @UnitId
IF @IsComplete_Building = 1 or @IsComplete_Unit = 1
BEGIN
RAISERROR (@ErrorMsg, 16, 1);
ROLLBACK TRANSACTION
END
END
----------------------------------------------------------------------------------------------------
END
SQL 服务器 2016 由 ASP.NET 4.6.2 MVC Web 应用程序访问
我有 table "Building",一个建筑可以有多个 "Components"。例如,Building1 有 Component1 和 Component2 ... etc
有人要求我能够锁定建筑物。锁定意味着无法再修改组件 (CREATE/UPDATE/DELETE)。好吧,正如您想象的那样,这是一个巨大的应用程序,一个组件可以在 100 多个地方进行修改。甚至没有人能回答这个问题,"Where all do I need to lock?"。
我的想法是锁定所有我能想到的地方,然后作为安全网创建一个 SQL 触发器,如果组件 table "IsLocked BIT" 上的列是真的。目前,我知道组件是否被锁定的唯一方法是 IsLocked 列是否等于 true。
所以,我说了这么多。如果正在修改的行的列 IsLocked = 1,我如何创建一个 SQL 服务器触发器来防止一行数据被修改?
编辑 1 在我看来,这不是重复的。使用 Instead of Delete 或 Instead of... 对我不起作用。如果我执行而不是...,那么在其中我将需要提供提交逻辑。我不想提供提交逻辑。我只想 运行 在插入、更新、删除之前进行检查。
编辑 2 - 而不是 Update/Delete 是最佳选择 如果不是...是我的最佳选择,那么有人可以使用 update/delete 来重写我的内容吗?我不知道该怎么做。请记住,请求将来自网络应用程序。我不知道他们是在更新一列还是整个实体,或者他们将传递什么。我知道我写的方式是它会捕获任何插入/update/delete 并在锁定时阻止它。如果有更好的方法请写出来并说明为什么更好。
这是我想出的解决方案:
ALTER TRIGGER [dbo].[PreventLockedModification]
ON [dbo].[Component]
FOR INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
--DETERMINE INSERT(I) UPDATE(U) OR DELETE(D)
----------------------------------------------------------------------------------------------------
DECLARE @action as char(1);
SET @action = 'I'; -- Set Action to Insert by default.
IF EXISTS(SELECT * FROM DELETED)
BEGIN
SET @action =
CASE
WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
ELSE 'D' -- Set Action to Deleted.
END
END
----------------------------------------------------------------------------------------------------
DECLARE @ErrorMsg nvarchar(100) = 'This row is locked and cannot be updated';
DECLARE @IsLocked bit;
DECLARE @BuildingId bigint;
DECLARE @UnitId bigint;
DECLARE @IsComplete_Building bit;
DECLARE @IsComplete_Unit bit;
----------------------------------------------------------------------------------------------------
IF @action = 'U' or @action = 'D'
BEGIN
SELECT @IsLocked = IsLocked FROM deleted;
IF @IsLocked = 1
BEGIN
RAISERROR (@ErrorMsg, 16, 1);
ROLLBACK TRANSACTION
END
END
----------------------------------------------------------------------------------------------------
ELSE IF @action = 'I'
BEGIN
SELECT @BuildingId = BuildingId FROM inserted;
SELECT @UnitId = UnitId FROM inserted;
SELECT @IsComplete_Building = IsComplete FROM Building WHERE BuildingId = @BuildingId
SELECT @IsComplete_Unit = IsComplete FROM Unit WHERE UnitId = @UnitId
IF @IsComplete_Building = 1 or @IsComplete_Unit = 1
BEGIN
RAISERROR (@ErrorMsg, 16, 1);
ROLLBACK TRANSACTION
END
END
----------------------------------------------------------------------------------------------------
END