Запрет отправки задачи большому количеству пользователей

17 0

Предисловие

В далекой-далекой галактике на крупном-крупном предприятии в целях автоматизации бизнес-процессов была внедрена система 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

Здесь была использована та же самая константа, но при желании можно создать еще одну.

Данные триггеры срабатывают при добавлении каждой новой записи, поэтому в случае с несколькими тысячами пользователей возникновению диалога с ошибкой будет предшествовать довольно продолжительная пауза… но это, согласитесь, совсем несущественно по сравнению с возможными последствиями.

За помощь в написании триггера спасибо Петру Федотову, за задачу, породившую идею – Евгению Петренко

Пока комментариев нет.

Авторизуйтесь, чтобы написать комментарий