Предисловие
В далекой-далекой галактике на крупном-крупном предприятии в целях автоматизации бизнес-процессов была внедрена система DIRECTUM, и пользователей в ней было зарегистрировано не абы сколько, а несколько тысяч. Пользователей – несколько тысяч, а администратор – один, и уж очень ему надоело исправлять последствия того, что кто-нибудь нет-нет, да и отправит задачу на всех пользователей разом. Стал администратор думать и гадать, как с этой напастью бороться…
* * *
Несмотря на сказочную подоплеку предисловия, проблема вполне себе реальна. И поскольку стандартных средств для ее решения в системе пока не наблюдается, мы пойдем тернистым путем написания триггера.
Шаг 1. Задаем максимальное количество пользователей
Прежде всего, стоит заметить, что максимальное количество пользователей, для которого необходимо запретить отправку задачи – вещь относительная: кто-то решит ввести ограничение по всем пользователям, кто-то – по самой многочисленной группе, а кто-то вообще будет исходить из собственных представлений о производительности. Поэтому лучше всего сделать данный параметр изменяемым, а именно – создать константу в компоненте «Константы». Назовем ее UserRestrict и зададим значение, например, 100:
Шаг 2. Создаем сообщение об ошибке
При помощи SQL-запроса в Management Studio создадим сообщение, которое будет возникать при срабатывании условия триггера. Код сообщения (20012) и текст могут быть произвольными.
INSERT XErrors(ErrCode, ErrGroup, Description, SrvCode, ErrType, Sost)
values(20012, 'XMBMSG', 'Too many users!', null, 16, 'Н')
UPDATE XErrors
SET Sost='З'
WHERE ErrCode=20012 AND Sost='Н'
Диалоговое окно сообщения будет выглядеть так:
Шаг 3. Пишем триггер
SQL-запросом создадим непосредственно триггер для таблицы SBTaskRoute, в которой хранятся данные об этапах маршрутов задач… «Стоп!» – скажете вы – «а почему именно для SBTaskRoute? Есть ведь и другие таблицы ЗЗУ!» Дело в том, что в данной таблице присутствует поле Number, в которое записываются номера этапов. Выглядит это следующим образом: при отправке задачи 50-ти пользователям в данной таблице создастся столько же записей, и значение поля Number будет увеличиваться от 1 до 50. Данная особенность выглядит крайне удобной для решения поставленной задачи, ну а дальше уже дело техники.
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE TRIGGER [dbo].[PerformNumbRestrict] ON [dbo].[SBTaskRoute] AFTER INSERT
AS
-- объявляем переменные
DECLARE
@MainTaskID INT, — ИД задачи
@MaxPerformNumber INT, — максимальное возможное кол-во исполнителей
@InRoutePerformers INT — кол-во исполнителей в текущей задаче
-- получаем ИД задачи
SET @MainTaskID = (SELECT TaskID FROM INSERTED)
-- получаем максимальное возможное кол-во исполнителей из константы
SET @MaxPerformNumber = (SELECT Value FROM MBConst WHERE Const = 'UserRestrict')
-- если константа не заполнена, за максимальное кол-во исполнителей...
IF @MaxPerformNumber = NULL
BEGIN
— ...принимаем кол-во пользователей в группе "Все пользователи"
SET @MaxPerformNumber = (SELECT
COUNT(UsersFromGroup.PolzovatelT)
FROM
MBAnalit AS Users,
MBAnalit AS Groups,
MBAnValR AS UsersFromGroup
WHERE
Users.Vid = (SELECT Vid FROM MBVidAn WHERE Kod = 'ПОЛ')
AND Users.XRecStat = '+'
AND Groups.Vid = (SELECT Vid FROM MBVidAn WHERE Kod = 'ГПЛ')
AND Groups.Analit = UsersFromGroup.Analit
AND UsersFromGroup.PolzovatelT = Users.Analit
AND Users.Sost = 'Д'
AND UsersFromGroup.Analit = (SELECT Analit FROM MBAnalit WHERE Dop = 'ВСЕ')
)
END
-- получаем кол-во исполнителей в текущей задаче, равное кол-ву этапов задачи
SET @InRoutePerformers = (SELECT Number FROM INSERTED WHERE TaskID = @MainTaskID)
-- если кол-во исполнителей в текущей задаче равно максимальному...
IF @InRoutePerformers = @MaxPerformNumber
BEGIN
— ...откатываем действие и вызываем сообщение об ошибке
ROLLBACK TRANSACTION
EXEC XRaisError @ErrCode = 20012
RETURN
END
GO
В дополнение. Решаем вопрос с наблюдателями
Искушенный пользователь, вероятно, еще в самом начале задался вопросом: а с наблюдателями как быть? Что ж, вопрос резонный. В этом случае придется писать отдельный триггер еще и для таблицы SBTaskObserv, в которой хранятся данные о наблюдателях. Выглядеть он будет практически так же, как и предыдущий, за одним существенным отличием: у SBTaskObserv отсутствует счетчик наподобие Number, поэтому считать записи в таблице будем при помощи SQL-функции COUNT. С каждой новой записью возвращаемое функцией значение будет увеличиваться и в итоге достигнет ограничения.
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE TRIGGER [dbo].[ObservNumbRestrict] ON [dbo].[SBTaskObserv] AFTER INSERT
AS
-- объявляем переменные
DECLARE
@MainTaskID INT, — ИД задачи
@MaxObservNumber INT, — макисмальное возможное кол-во наблюдателей
@InRouteObservers INT — кол-во наблюдателей в текущей задаче
-- получаем ИД задачи
SET @MainTaskID = (SELECT TaskID FROM INSERTED)
-- получаем максимальное возможное кол-во наблюдателей из константы
SET @MaxObservNumber = (SELECT Value FROM MBConst WHERE Const = 'UserRestrict')
-- если константа не заполнена, за максимальное кол-во наблюдателей...
IF @MaxObservNumber = NULL
BEGIN
— ...принимаем кол-во пользователей в группе "Все пользователи"
SET @MaxObservNumber = (SELECT
COUNT(UsersFromGroup.PolzovatelT)
FROM
MBAnalit AS Users,
MBAnalit AS Groups,
MBAnValR AS UsersFromGroup
WHERE
Users.Vid = (SELECT Vid FROM MBVidAn WHERE Kod = 'ПОЛ')
AND Users.XRecStat = '+'
AND Groups.Vid = (SELECT Vid FROM MBVidAn WHERE Kod = 'ГПЛ')
AND Groups.Analit = UsersFromGroup.Analit
AND UsersFromGroup.PolzovatelT = Users.Analit
AND Users.Sost = 'Д'
AND UsersFromGroup.Analit = (SELECT Analit FROM MBAnalit WHERE Dop = 'ВСЕ')
)
END
-- считаем кол-во наблюдателей в текущей задаче
SET @InRouteObservers = (SELECT COUNT(Observer) FROM SBTaskObserv WHERE TaskID = @MainTaskID)
-- если кол-во наблюдателей в текущей задаче равно максимальному...
IF @InRouteObservers = @MaxObservNumber
BEGIN
— ...откатываем действие и вызываем сообщение об ошибке
ROLLBACK TRANSACTION
EXEC XRaisError @ErrCode = 20012
RETURN
END
GO
Здесь была использована та же самая константа, но при желании можно создать еще одну.
Данные триггеры срабатывают при добавлении каждой новой записи, поэтому в случае с несколькими тысячами пользователей возникновению диалога с ошибкой будет предшествовать довольно продолжительная пауза… но это, согласитесь, совсем несущественно по сравнению с возможными последствиями.
За помощь в написании триггера спасибо Петру Федотову, за задачу, породившую идею – Евгению Петренко.
Авторизуйтесь, чтобы написать комментарий