|
04.09.2006, 13:19 | #1 |
Columbus IT
|
Не работает RLS по связанной таблице. Так и должно быть?
Создаю правило RLS для VendTransOpen. В форме запроса добавляю связнную таблицу - VendTrans. По ней накладываю условие (Одобрено = "ХХХ", нужны только открытые проводки по поставщикам, VendTrans по которым одобрены именно тем-то).
Смотрю "Поставщики - Функции - Сопоставление открытых проводок" - видно все. Вопрос. Правильно ли я понимаю, что если я в форме настройки запроса RLS присоединяю связную таблицу и условие накладываю по ней, это работать не будет? |
|
04.09.2006, 13:41 | #2 |
NavAx
|
RLS на связанных таблицах не работает. Проверено.
Сложные запросы в RLS Последний раз редактировалось Roman777; 04.09.2006 в 13:44. |
|
|
За это сообщение автора поблагодарили: kosenkov (1). |
04.09.2006, 13:49 | #3 |
Axapta
|
Цитата:
Вопрос. Правильно ли я понимаю, что если я в форме настройки запроса RLS присоединяю связную таблицу и условие накладываю по ней, это работать не будет?
|
|
|
За это сообщение автора поблагодарили: kosenkov (1). |
04.09.2006, 14:39 | #4 |
Columbus IT
|
Спасибо.
Тогда другой вопрос. Есть такая тема - группы закупщиков. Она присутствует в поставщиках, закупках, строках финансовых журналов. Есть желание использовать группу закупщиков как средство разграничения доступа менеджеров отдела закупок к данным посредством RLS. По-моему, группа закупщиков как раз под это и нужна. Доступ к самим закупках разграничивается замечательно. Но есть немало отчетов, построенных на VendTrans, VendTransOpen, VendSetllement - а в этих таблицах группы закупщиков нет. Соответсвенно, RLS настроить нельзя. Вопрос: как корректней решить эту задачу? - Добавлять поля, смотреть где создаются записи - делать модификации - и юзать RLS? - Писать сбоку от RLS пристройку для нужных отчетов? - Как-то еще? |
|
05.09.2006, 08:15 | #5 |
Мрачный тип
|
Ну если Вы в состоянии настолько глубоко влезть в системные классы(если оно вообще классами реализуется, а не в ядре), то логика в общих чертах такова :
нужно чтобы неким классом после формирования структуры запроса на клиенте/сервере приложений и перед отправкой на сервер БД проходилось все дерево датасорсов сформированной структуры запроса и для каждого бы датасорса проверялся и изменялся/добавлялся невидимый и недоступный для редактирования range согласно условий, заданных для данного пользователя и данной таблицы датасорса в RLS. Тогда Ваша задача (отчет по VendTrans'у c при-join'енным VendTable, который ограничен по условиям из RLS) будет выполнима, как и вообще любой отчет. Я умом это понимаю, но где и как копать - пока представления не имею, хотя подобное самому необходимо до зарезу ... Сами пока пишем для каждого сложного отчета надстройки, так что ежели чего нароете - дайте знать, пжалста Последний раз редактировалось TasmanianDevil; 05.09.2006 в 08:34. |
|
05.09.2006, 09:15 | #6 |
Участник
|
Если решать вопрос по месту, то везде, где нужно ограничение по группе поставщиков, надо делать exist join на группу, решение простое и напрашивается само собой. Если его удачно обернуть, сведется к вставке вызова некоего метода везде, где требуется.
Альтернатива - свой RLS (модифицированный RLS), его подсунуть можно в sysSetupFormRun.init, но это большая и серьезная вещь. C уважением, itfs. |
|
|
За это сообщение автора поблагодарили: kosenkov (1). |
06.09.2006, 11:12 | #7 |
Axapta
|
А что если вот так исправить метод new в SysQueryRun. Какие минусы? Что не будет работать, если запрос через X++ - понятно. Что не будет, если получится много ExistJoin - понятно. Что еще? Есть что-нить глобально неправильное? Будет ли работать в простейших случаях?
X++: public void new(anytype _p1) { // custom RLS, OIP, 05.09.06 --> int i,j,k; QueryBuildRange r; QueryBuilddatasource ds; QueryBuilddatasource childDS; QueryBuilddatasource restrictDS; Query q; SysRecordLevelSecurity RLSTable; Query restriction; userGroupId groupId; userGroupList groupList; // custom RLS, OIP, 05.09.06 <-- if (_p1) { super (_p1); if (this.args() && !this.args().caller() && typeOf(_p1) == Types::Class && !SysdictClass::isEqualOrSuperClass(classidget(_p1), classNum(Query))) { this.args().caller(_p1); } // custom RLS, OIP, 05.09.06 --> q = this.query(); { for(i=1; i<= q.dataSourceCount(); i++) { ds = q.dataSourceNo(i); while select RLSTable where RLSTable.tabId == ds.table() join groupList where groupList.groupId == RLSTable.groupId && groupList.userId == curUserId() { if(RLSTable.restriction != conNull() && sysQuery::isPackedOk(RLSTable.restriction)) { restriction = new QueryRun(RLSTable.restriction).query(); if(restriction.dataSourceCount()>1) { for(j=2;j<= restriction.dataSourceCount();j++) { restrictDS = restriction.dataSourceNo(j); if (!SysQuery::tableOccurrence(q, restrictDS.table(), q.dataSourceCount())) { childDS = ds.addDataSource(restrictDS.table()); childDS.relations(true); childDS.joinMode(JoinMode::ExistsJoin); childDS.fetchMode(QueryFetchMode::One2One); } else { childDS = q.dataSourceTable(restrictDS.table()); } for(k=1;k<=restrictDS.rangeCount();k++) { r = restrictDS.range(k); SysQuery::findOrCreateRange(childDs, r.field()).value(r.value()); } } } } } } } } // custom RLS, OIP, 05.09.06 <-- loadLastUsedQuery = true; saveQueryPrUser = true; allowSave = true; allowAddRange = QueryAllowAdd::AllFields; allowAddSorting = QueryAllowAdd::AllFields; showSorting = true; } если например настроил RLS на VendTable (в форме Запросы в РЛС приджойнил скажем RContractTable с критерием по Ответственному лицу равным "ИИИ" - у нас таких поставщиков 2) и везде, во всех формах на основе VendTable и отчетах только эти 2 поставщика отображаются. И даже лукап по поставщикам тоже только этих двух отображает. PS Это пока самая первая версия кода. Там еще много чего можно исправлять. Поэтому интересует лишь возможность именно такого подхода. Последний раз редактировалось oip; 06.09.2006 в 12:42. |
|
06.09.2006, 13:19 | #8 |
Axapta
|
Исправил кое-что:
X++: public void new(anytype _p1) { // custom RLS, OIP, 05.09.06 --> int i,j,k; QueryBuildRange r; QueryBuilddatasource ds; QueryBuilddatasource childDS; QueryBuilddatasource intDS; QueryBuilddatasource restrictDS; Query q; SysRecordLevelSecurity RLSTable; Query restriction; userGroupId groupId; userGroupList groupList; // custom RLS, OIP, 05.09.06 <-- if (_p1) { super (_p1); if (this.args() && !this.args().caller() && typeOf(_p1) == Types::Class && !SysdictClass::isEqualOrSuperClass(classidget(_p1), classNum(Query))) { this.args().caller(_p1); } // custom RLS, OIP, 05.09.06 --> q = this.query(); for(i=1; i<= q.dataSourceCount(); i++) { ds = q.dataSourceNo(i); while select RLSTable where RLSTable.tabId == ds.table() join groupList where groupList.groupId == RLSTable.groupId && groupList.userId == curUserId() { if(RLSTable.restriction != conNull() && sysQuery::isPackedOk(RLSTable.restriction)) { restriction = new QueryRun(RLSTable.restriction).query(); if(restriction.dataSourceCount()>1) { for(j=2;j<= restriction.dataSourceCount();j++) { restrictDS = restriction.dataSourceNo(j); intDS = restrictDS.parentDataSource(); if (!SysQuery::tableOccurrence(q, restrictDS.table(), q.dataSourceCount())) { childDS = q.dataSourceTable(intDS.table()).addDataSource(restrictDS.table()); childDS.relations(true); childDS.joinMode(JoinMode::ExistsJoin); childDS.fetchMode(QueryFetchMode::One2One); } else { childDS = q.dataSourceTable(restrictDS.table()); } for(k=1;k<=restrictDS.rangeCount();k++) { r = restrictDS.range(k); SysQuery::findOrCreateRange(childDs, r.field()).value(r.value()); } } } } } } } // custom RLS, OIP, 05.09.06 <-- loadLastUsedQuery = true; saveQueryPrUser = true; allowSave = true; allowAddRange = QueryAllowAdd::AllFields; allowAddSorting = QueryAllowAdd::AllFields; showSorting = true; } Последний раз редактировалось oip; 06.09.2006 в 15:11. |
|
06.09.2006, 18:08 | #9 |
Axapta
|
Ну хоть кто-нибудь, ну покритикуйте, ну пожалуйста.
PS Может переместить ветку в "Программирование"? Или там пересоздать тему? |
|
|
За это сообщение автора поблагодарили: itfs (1). |
07.09.2006, 12:48 | #10 |
Участник
|
Хорошая идея, раздвигает возможности RLS на 1 шаг по связям.
Из недостатков: 1. фильрт можно руками снять, надо его лочить; 2. даже залоченный фильтр можно сбить (глюк аксапты), поэтому нужно, чтобы фильтр восстанавливался всякий раз на executeQuery(). 3. забавный эффект, если забыть сами RContractTable ограничить ... С уважением, itfs. |
|
07.09.2006, 12:53 | #11 |
Axapta
|
Цитата:
Сообщение от itfs
Хорошая идея, раздвигает возможности RLS на 1 шаг по связям.
Цитата:
1. фильрт можно руками снять, надо его лочить;
Цитата:
2. даже залоченный фильтр можно сбить (глюк аксапты), поэтому нужно, чтобы фильтр восстанавливался всякий раз на executeQuery().
Цитата:
3. забавный эффект, если забыть сами RContractTable ограничить ...
Следующая версия, исправлена возможность снятия фильтра руками. Спасибо, itfs. X++: public void new(anytype _p1) { // custom RLS, OIP, 05.09.06 --> int i,j,k; QueryBuildRange r; QueryBuilddatasource ds; QueryBuilddatasource childDS; QueryBuilddatasource intDS; QueryBuilddatasource restrictDS; Query q; SysRecordLevelSecurity RLSTable; Query restriction; userGroupId groupId; userGroupList groupList; // custom RLS, OIP, 05.09.06 <-- if (_p1) { super (_p1); if (this.args() && !this.args().caller() && typeOf(_p1) == Types::Class && !SysdictClass::isEqualOrSuperClass(classidget(_p1), classNum(Query))) { this.args().caller(_p1); } // custom RLS, OIP, 05.09.06 --> q = this.query(); for(i=1; i<= q.dataSourceCount(); i++) { ds = q.dataSourceNo(i); while select RLSTable where RLSTable.tabId == ds.table() join groupList where groupList.groupId == RLSTable.groupId && groupList.userId == curUserId() { if(RLSTable.restriction != conNull() && sysQuery::isPackedOk(RLSTable.restriction)) { restriction = new QueryRun(RLSTable.restriction).query(); if(restriction.dataSourceCount()>1) { for(j=2;j<= restriction.dataSourceCount();j++) { restrictDS = restriction.dataSourceNo(j); intDS = restrictDS.parentDataSource(); if (!SysQuery::tableOccurrence(q, restrictDS.table(), q.dataSourceCount())) { childDS = q.dataSourceTable(intDS.table()).addDataSource(restrictDS.table()); childDS.relations(true); childDS.joinMode(JoinMode::ExistsJoin); childDS.fetchMode(QueryFetchMode::One2One); } else { childDS = q.dataSourceTable(restrictDS.table()); } for(k=1;k<=restrictDS.rangeCount();k++) { r = SysQuery::findOrCreateRange(childDs, restrictDS.range(k).field()); r.value(restrictDS.range(k).value()); r.status(RangeStatus::Hidden); } } } } } } } // custom RLS, OIP, 05.09.06 <-- loadLastUsedQuery = true; saveQueryPrUser = true; allowSave = true; allowAddRange = QueryAllowAdd::AllFields; allowAddSorting = QueryAllowAdd::AllFields; showSorting = true; } Последний раз редактировалось oip; 07.09.2006 в 22:54. |
|
|
За это сообщение автора поблагодарили: mazzy (5), anykey (1). |
07.09.2006, 13:19 | #12 |
Участник
|
Почему на 1?
Неправильно выразился, имел ввиду, что каждую зависимую таблицу, которую хочется ограничить нужно оформить отдельной настройкой, это просто соображение по поводу простоты настройки, как и соображение (3). Что касается сбить. то в вашем случае, когда он hidden, открываем форму фильтра, выбираем таблицу клиентов и по правой клавише удалить ... понимаю, экзотика, но злонамеренное действие совершить можно. С уважением, itfs. |
|
|
За это сообщение автора поблагодарили: oip (2). |
07.09.2006, 13:22 | #13 |
Axapta
|
Цитата:
Сообщение от itfs
Неправильно выразился, имел ввиду, что каждую зависимую таблицу, которую хочется ограничить нужно оформить отдельной настройкой
Цитата:
Что касается сбить. то в вашем случае, когда он hidden, открываем форму фильтра, выбираем таблицу клиентов и по правой клавише удалить ... понимаю, экзотика, но злонамеренное действие совершить можно.
Последний раз редактировалось oip; 07.09.2006 в 13:24. |
|
01.11.2006, 11:49 | #14 |
Axapta
|
В процессе работы выяснилось, что строки
X++: for(k=1;k<=restrictDS.rangeCount();k++)
{
r = SysQuery::findOrCreateRange(childDs, restrictDS.range(k).field());
r.value(restrictDS.range(k).value());
r.status(RangeStatus::Hidden);
} X++: for(k=1;k<=restrictDS.rangeCount();k++)
{
r = childDs.addRange(restrictDS.range(k).field());
r.value(restrictDS.range(k).value());
r.status(RangeStatus::Hidden);
} |
|
17.11.2006, 16:37 | #15 |
Axapta
|
Была еще небольшая ошибка, выбирались все РЛС, а не только те, которые настроены для текущей компании.
X++: public void new(anytype _p1) { // custom RLS, OIP, 05.09.06 --> int i,j,k; QueryBuildRange r; QueryBuilddatasource ds; QueryBuilddatasource childDS; QueryBuilddatasource intDS; QueryBuilddatasource restrictDS; Query q; SysRecordLevelSecurity RLSTable; Query restriction; userGroupId groupId; userGroupList groupList; // custom RLS, OIP, 05.09.06 <-- if (_p1) { super (_p1); if (this.args() && !this.args().caller() && typeOf(_p1) == Types::Class && !SysdictClass::isEqualOrSuperClass(classidget(_p1), classNum(Query))) { this.args().caller(_p1); } // custom RLS, OIP, 05.09.06 --> q = this.query(); for(i=1; i<= q.dataSourceCount(); i++) { ds = q.dataSourceNo(i); while select RLSTable where RLSTable.tabId == ds.table() && RLSTable.companyId == curext() join groupList where groupList.groupId == RLSTable.groupId && groupList.userId == curUserId() { if(RLSTable.restriction != conNull() && sysQuery::isPackedOk(RLSTable.restriction)) { restriction = new QueryRun(RLSTable.restriction).query(); if(restriction.dataSourceCount()>1) { for(j=2;j<= restriction.dataSourceCount();j++) { restrictDS = restriction.dataSourceNo(j); intDS = restrictDS.parentDataSource(); if (!SysQuery::tableOccurrence(q, restrictDS.table(), q.dataSourceCount())) { childDS = q.dataSourceTable(intDS.table()).addDataSource(restrictDS.table()); childDS.relations(true); childDS.joinMode(JoinMode::ExistsJoin); childDS.fetchMode(QueryFetchMode::One2One); } else { childDS = q.dataSourceTable(restrictDS.table()); } for(k=1;k<=restrictDS.rangeCount();k++) { r = childDs.addRange(restrictDS.range(k).field()); r.value(restrictDS.range(k).value()); r.status(RangeStatus::Hidden); } } } } } } } // custom RLS, OIP, 05.09.06 <-- loadLastUsedQuery = true; saveQueryPrUser = true; allowSave = true; allowAddRange = QueryAllowAdd::AllFields; allowAddSorting = QueryAllowAdd::AllFields; showSorting = true; } |
|
|
За это сообщение автора поблагодарили: maximka (1). |
07.12.2006, 12:04 | #16 |
Участник
|
В отчете "Доступ на уровне записей" не указывается таблица на которую и накладывается доступ, а только та на которую наложено Условие.
|
|
16.03.2007, 16:50 | #17 |
Участник
|
На "Таблицу складского журнала" настроен RLS по связанной таблице "Строки складского журнала"
Захажу под пользователем в "Таблицу складских журналов" нажимаю "Фильтр" и спокойно удаляю связанную таблицу. Теперь пользователю доступны все "Складские журналы" |
|
11.04.2007, 13:27 | #18 |
Участник
|
Цитата:
X++: this.origQueryPack( q.pack(false) ); PS. Не учел возможное наличие диналинк. Добавил false в pack()
__________________
Axapta v.3.0 sp5 kr2 Последний раз редактировалось AndyD; 11.04.2007 в 18:00. |
|
|
За это сообщение автора поблагодарили: oip (9). |
10.04.2007, 19:35 | #19 |
Участник
|
Олег, воспользовался вашим кодом и наткнулся на такую проблему.
Создаю две группы пользователей. Накладываю ограничения на таблицу ProdTable по связанным таблицам. Отношу пользоватлеля к обеим группам, но в результате получаю ограничения только одного пользователя. Первая группа пользователей: ProdTable ограничение по полю номенклатура, и по полю статус производственного заказа. Вторая группа пользователей: ProdTable критерий по статусу производственного заказа. ProdTable связываю с таблицей ProdBOM (связь 1:n). Накладываю ограничения по полю номенклатура ProdBOM. ProdTable связываю с таблицей ProdJournalBOM (связь 1:n) критерий не задаю. Если пользователь относится к одной из групп, то видит нужные записи. Если к обоим, то производственные заказы второй группы. План исполнения: Код: SELECT A.ITEMID,A.NAME,A.PRODGROUPID,A.PRODSTATUS,A.PRODTYPE,A.QTYSCHED,A.QTYSTUP,A.DLVDATE,A.STUPDATE,A.FINISHEDDATE,A.SCHEDSTART,A.SCHEDEND,A.HEIGHT,A.WIDTH,A.DEPTH,A.DENSITY,A.QTYCALC,A.REALDATE,A.RESERVATION,A.PRODPOSTINGTYPE,A.INVENTTRANSID,A.DIMENSION,A.DIMENSION2_,A.DIMENSION3_,A.INVENTREFTYPE,A.INVENTREFID,A.INVENTREFTRANSID,A.COLLECTREFLEVEL,A.COLLECTREFPRODID,A.BOMDATE,A.BACKORDERSTATUS,A.PRODPOOLID,A.PROFITSET,A.CALCDATE,A.REMAININVENTPHYSICAL,A.BOMID,A.DEL_CONFIGID,A.REQPLANIDSCHED,A.REQPOID,A.REFLOOKUP,A.PRODID,A.INVENTDIMID,A.PRODORIGID,A.PRODPOSITION,A.CREATEDDATE,A.CREATEDTIME,A.CREATEDBY,A.RECVERSION,A.RECID,B.INVENTDIMID,B.INVENTBATCHID,B.INVENTSERIALID,B.INVENTLOCATIONID,B.CONFIGID,B.INVENTSIZEID,B.INVENTCOLORID,B.INVENTGTDID_RU,B.EMPLRESPONSIBLEID_RU,B.RECVERSION,B.RECID FROM PRODTABLE A,INVENTDIM B WHERE ((A.DATAAREAID=?) AND (((A.PRODSTATUS=?) OR ((((A.ITEMID=?) OR (A.ITEMID=?)) OR (A.ITEMID=?)) AND ((A.BACKORDERSTATUS>=?) AND (A.BACKORDERSTATUS<=?)))) AND ((A.PRODSTATUS=?) OR ((((A.ITEMID=?) OR (A.ITEMID=?)) OR (A.ITEMID=?)) AND ((A.BACKORDERSTATUS>=?) AND (A.BACKORDERSTATUS<=?)))))) AND ((B.DATAAREAID=?) AND (A.INVENTDIMID=B.INVENTDIMID)) AND EXISTS (SELECT 'X' FROM PRODJOURNALBOM C WHERE ((C.DATAAREAID=?) AND (A.PRODID=C.PRODID)) AND EXISTS (SELECT 'X' FROM PRODBOM D WHERE ((D.DATAAREAID=?) AND ((((((D.ITEMID=?) OR (D.ITEMID=?)) OR (D.ITEMID=?)) AND (A.PRODID=D.PRODID)) AND ((((((((D.ITEMID=?) OR (D.ITEMID=?)) OR (D.ITEMID=?)) OR (D.ITEMID=?)) OR (D.ITEMID LIKE ? ESCAPE '\' )) OR (D.ITEMID LIKE ? ESCAPE '\' )) OR (D.ITEMID LIKE ? ESCAPE '\' )) OR (D.ITEMID LIKE ? ESCAPE '\' ))) AND ((((((((D.ITEMID=?) OR (D.ITEMID=?)) OR (D.ITEMID=?)) OR (D.ITEMID=?)) OR (D.ITEMID LIKE ? ESCAPE '\' )) OR (D.ITEMID LIKE ? ESCAPE '\' )) OR (D.ITEMID LIKE ? ESCAPE '\' )) OR (D.ITEMID LIKE ? ESCAPE '\' )))))) ORDER BY A.DATAAREAID DESC,A.PRODID DESC OPTION(FAST 1,LOOP JOIN) |
|
20.04.2007, 10:04 | #20 |
Участник
|
Пытаюсь настроить на Произв. заказы RLS. Произв. заказы -> Спецификация производства -> Складская аналитика.
В таблице Складская аналитика в поле Склад указываю значение "Склад 1". Захожу под пользователем и вижу Произв. заказы с аналитикой "Склад 1", т.е. RLS настраивается по запросу Произв. заказы -> Складская аналитика. Как решить эту проблему? Последний раз редактировалось oxbacc; 20.04.2007 в 10:48. |
|
Теги |
faq, rls, законченный пример, полезное, права доступа на уровне записей (rls), связанная таблица, связанные сущности |
|
|