Check-in и check-out малой кровью
Известно — там, где не предусмотрены стандартные средства чего-либо, обязательно (обязательно) найдется свой Левша, который с помощью молотка, веревки и смекалки (!) сделает так, как никому и не снилось.
Сегодня в студии разбирается вопрос организации работы роты программистов над отдельно взятым проектом. Боевая задача — запретить одновременное редактирование одного и того же объекта разными людьми.
На помощь приходят все те же триггеры на таблицу Объект (SQL триггеры, естественно). Дополнительно потребуется таблица [Object Locking], в которую пишется лог check-in’ов и check-out’ов. Архив, содержащий скрипт и таблицу:
nav-checkout (1,6 KiB, 1 731 hits)
Теперь, чтобы получить возможность делать изменения (а точнее, сохранять их, но к этому все быстро привыкают), надо записать свой логин в строку с версией объекта.
Убрать логин из версии — означает, снять блокировку.
Никто другой убрать логин не может — только сам поставивший.
Если у поставившего случился понос или золотуха, а снять надо, то решение очевидно — временно отключить сам триггер.
P.S. Подразумевается, что в команде работают адекватные люди, понимающие выгоды от хорошей постановки процесса :) Остальных — выжигать каленым железом, либо перевоспитывать (вести себя по-отечески, т.е. объяснять, наказывать и прочая). Это уж кому как нравится.
-- если объект взят другим пользователем, вставка в лог
CREATE TRIGGER dbo.Trg_Cath_CheckInOut ON dbo.Object
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
DECLARE @old_blocked_by_user VARCHAR(20), @new_blocked_by_user VARCHAR(20)
DECLARE @old_size INT, @new_size INT
DECLARE @old_version VARCHAR(250), DECLARE @new_version VARCHAR(250)
SELECT @old_size=[BLOB SIZE], @old_version=[Version List]
FROM deleted
SELECT @new_size=[BLOB SIZE], @new_version=[Version List]
FROM inserted
SELECT @old_blocked_by_user =u.[USER ID]
FROM deleted d
INNER JOIN dbo.[USER] u
ON CHARINDEX(u.[USER ID], d.[Version List])<>0-- and u.[User ID]<>SUSER_NAME()
SELECT @new_blocked_by_user =u.[USER ID]
FROM inserted i
INNER JOIN dbo.[USER] u
ON CHARINDEX(u.[USER ID], i.[Version List])<>0
--проверяем логин на старой версии записи
IF ISNULL(@old_blocked_by_user, '')<>SUSER_NAME() AND @old_blocked_by_user<>'' AND ISNULL(@old_size, -1)>=0 BEGIN
RAISERROR ('Объект занят пользователем %s', 16, 1, @old_blocked_by_user)
ROLLBACK TRANSACTION
RETURN
END
--если модификация
--проверяем логин на новой версии записи, при условии что изменился код объекта
--и вставляем записи в лог при условии что сменился user
IF ISNULL(@old_size, -1)>=0 AND ISNULL(@new_size, -1)>=0 BEGIN
IF @old_size<>@new_size AND ISNULL(@new_blocked_by_user, '')<>SUSER_NAME() BEGIN
RAISERROR('Для модификации объекта необходимо ввести логин и задачу в списке версий', 16, 1)
ROLLBACK TRANSACTION
RETURN
END
IF ISNULL(@new_blocked_by_user, '')=SUSER_NAME() AND
ISNULL(@old_blocked_by_user, '')<>SUSER_NAME() BEGIN
--check out
INSERT INTO dbo.[Object Locking]
([Object TYPE], [Object ID], [Object Version], [Checkout DT], [Checkin DT], [USER ID])
SELECT TYPE, ID, [Version List], GETDATE(), '17530101', SUSER_NAME()
FROM inserted
IF @@error<>0 BEGIN
RAISERROR('Ошибка при вставке в таблицу Object Locking', 16, 1)
ROLLBACK TRANSACTION
RETURN
END
END
IF ISNULL(@old_blocked_by_user, '')=SUSER_NAME() AND
ISNULL(@new_blocked_by_user, '')<>SUSER_NAME() BEGIN
--check in
UPDATE l
SET [Checkin DT]=GETDATE()
FROM [Object Locking] l
INNER JOIN inserted i
ON i.ID=l.[Object ID] AND i.TYPE=l.[Object TYPE]
AND YEAR([Checkin DT])=1753
IF @@error<>0 BEGIN
RAISERROR ('Ошибка при обновлении данных в таблице Object Locking', 16, 1)
ROLLBACK TRANSACTION
RETURN
END
END
END
END

Автор: Максим Репин
Количество статей, опубликованных автором: 4. Дополнительная информация об авторе появится вскоре.