Хотел бы поделиться изысканиями с коллегами.
После часов настройки MS SQL 2005 Reporting Services я сумел сделать в Report Builder простенький отчет матричного вида, показывающий, сколько времени отработали рабочие в разбивке по станкам. Для отчета была сформирована модель SMDL с таблицей ProdRouteTrans из перспективы Production.
Запустив полученный отчет, я был неприятно раздосадован тем, что в нем стояли одни нули, хотя проводки в БД были на месте. Возникло подозрение, что модель SMDL использует не таблицы, а ссылается на какие-то специальные view. Кроме того, я сделал наблюдение, что модели экспортируются из DAX все за раз без учета компаний. Сам SMDL - это здоровенный файл XML, для которого я не нашел графического редактора. Тем не менее, фильтр по компании в SMDL определенно отсутствовал.
Запустив SQL Server Profiler, я выделил собственно запрос, который идет к базе данных (извините за немецкие имена, модель SMDL была экспортирована с языком de-at):
X++:
SET DATEFIRST 1
SELECT
CAST(1 AS BIT) [c0_is_agg],
CAST(1 AS BIT) [c1_is_agg],
CAST(2 AS INT) [agg_row_count],
[PRODROUTETRANSWITHUSERIDS].[SummeGutmenge_Sum] [SummeGutmenge_Sum],
[PRODROUTETRANSWITHUSERIDS].[SummeStunden_Sum] [SummeStunden_Sum],
[PRODROUTETRANSWITHUSERIDS].[Mitarbeiter] [Mitarbeiter],
[PRODROUTETRANSWITHUSERIDS].[Ressource] [Ressource]
FROM
(
SELECT
SUM([PRODROUTETRANSWITHUSERIDS].[QTYGOOD]) [SummeGutmenge_Sum],
SUM([PRODROUTETRANSWITHUSERIDS].[HOURS]) [SummeStunden_Sum],
[PRODROUTETRANSWITHUSERIDS].[EMPLID] [Mitarbeiter],
[PRODROUTETRANSWITHUSERIDS].[WRKCTRID] [Ressource]
FROM
[DBO].[PRODROUTETRANSWITHUSERIDS] [PRODROUTETRANSWITHUSERIDS]
WHERE
[PRODROUTETRANSWITHUSERIDS].[WindowsID] = 'MF\evggla'
GROUP BY
[PRODROUTETRANSWITHUSERIDS].[EMPLID], [PRODROUTETRANSWITHUSERIDS].[WRKCTRID]
) [PRODROUTETRANSWITHUSERIDS]
ORDER BY
[Mitarbeiter], [Ressource]
Из этого запроса видно: (1) обращение идет не к таблице ProdRouteTrans, а к представалению PRODROUTETRANSWITHUSERIDS; (2) нет фильтра по компании; (3) есть фильтр по пользователю Windows
Определение самого представления, автоматически сформированного Аксаптой в момент экспорта моделей, вызывает ужас:
X++:
SELECT FINALLIST.WINDOWSID, dbo.PRODROUTETRANS.DATAAREAID, dbo.PRODROUTETRANS.RECVERSION, dbo.PRODROUTETRANS.RECID,
CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 1) > 0 THEN PRODID ELSE NULL END AS PRODID,
CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 2) > 0 THEN OPRNUM ELSE NULL END AS OPRNUM,
CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 3) > 0 THEN JOBID ELSE NULL END AS JOBID,
CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 4) > 0 THEN JOBTYPE ELSE NULL END AS JOBTYPE,
...
FROM (SELECT DISTINCT
USERDOMAINLIST.WINDOWSID, VIRTUALDOMAINLIST.COMPANY_ID, dbo.FIELDMASK(261, USERDOMAINLIST.USERINFO_USERID,
VIRTUALDOMAINLIST.COMPANY_ID) AS FIELDMASKSTRING, USERDOMAINLIST.USERINFO_USERID
FROM (SELECT dbo.VIRTUALDATAAREALIST.VIRTUALDATAAREA AS COMPANY_ID, dbo.COMPANYDOMAINLIST.DOMAINID
FROM dbo.VIRTUALDATAAREALIST INNER JOIN
dbo.COMPANYDOMAINLIST ON dbo.COMPANYDOMAINLIST.COMPANYID = dbo.VIRTUALDATAAREALIST.ID
WHERE (dbo.VIRTUALDATAAREALIST.VIRTUALDATAAREA IN
(SELECT DATAAREAID
FROM dbo.PRODROUTETRANS))
UNION
SELECT COMPANYID AS COMPANY_ID, DOMAINID
FROM dbo.COMPANYDOMAINLIST
WHERE (COMPANYID IN
(SELECT DATAAREAID
FROM dbo.PRODROUTETRANS))) AS VIRTUALDOMAINLIST INNER JOIN
(SELECT DISTINCT
dbo.WINDOWSID(dbo.USERINFO.NETWORKDOMAIN, dbo.USERINFO.NETWORKALIAS) AS WINDOWSID, TPERMS.DOMAINID,
dbo.USERGROUPLIST.GROUPID, dbo.USERINFO.ID AS USERINFO_USERID
FROM dbo.USERGROUPLIST INNER JOIN
dbo.USERINFO ON dbo.USERINFO.ID = dbo.USERGROUPLIST.USERID AND dbo.USERINFO.ENABLE = 1 INNER JOIN
(SELECT DOMAINID, GROUPID
FROM dbo.SYSSRSTABLEPERMISSIONS AS A
WHERE (TABID = 261)) AS TPERMS ON dbo.USERGROUPLIST.GROUPID = TPERMS.GROUPID OR
dbo.USERGROUPLIST.GROUPID = 'ADMIN') AS USERDOMAINLIST ON
USERDOMAINLIST.DOMAINID = VIRTUALDOMAINLIST.DOMAINID OR VIRTUALDOMAINLIST.DOMAINID = 'ADMIN' AND
USERDOMAINLIST.GROUPID = 'ADMIN') AS FINALLIST INNER JOIN
dbo.PRODROUTETRANS ON dbo.PRODROUTETRANS.DATAAREAID = FINALLIST.COMPANY_ID
Ключевая таблица здесь - это SYSSRSTABLEPERMISSIONS, которая была пустой! Неудивительно, что запрос не возвращал данных.
Системная для Аксапта таблица SYSSRSTABLEPERMISSIONS содержит представление всех прав доступа к полям и таблицам в Аксапта в разрезе доменов и групп. При этом таблица строится в методе Classes\xAccessRightsList\saveSecurityRights при принудительном задании прав доступа. Поскольку мой пользователь "MF\evggla" принадлежал только группе Admin, для этой группы в таблице записей не было.
После того, как я создал новую группу пользователей Test, Аксапта заполнила таблицу:
Представление PRODROUTETRANSWITHUSERIDS стало возвращать данные:
Отчет выдал результаты... просуммированные по всем компаниям в базе.
Выводы:
- DAX пытается вынудить Reporting Services учитывать собственные права доступа
- Если пользователь принадлежит только группе Admin, он не видит ничего
- Если вы создали новое поле, то данные не будут показаны даже при условии, что модели SMDL экспортированы заново, поскольку таблица SYSSRSTABLEPERMISSIONS не обновлена
- Если пользователь имеет права на домен, в который входит несколько компаний, отчеты показывают по умолчанию суммы по всем компаниям
- Если это так, то предотвратить это можно фильтром по компании в самом отчете
- Становится более понятно, почему пользователи DAX обязательно должны соответствовать пользователям Windows
- Reporting Services - это еще один способ обойти RLS