Forum Discussion
Manage Roles - Row level data restrictions
Hi all,
Working on row level data restrictions. I do have a Budget table by Sales representative. Every sales person only can see their own data, plus two managers that they can see the sales representatives reporting to them and finally Director having access to all the data. Somehow it's not working.
I have created a "Security Table" with the users and Sales Rep ID, what indicates which users can see each one (i.e.; meaning Director can see Sales Rep ID 1,2,3 & 4. Manager1 sales rep ID 1 and 2, Manager2 sales rep ID 3 and 4 and finally Sales rep1 only can see Sales rep ID 1 and so on...
Model view below with Relationships are both one to many.
Formula DAX use in the manage roles
Hi Msampedro
RLS filter needs to sit on DimSalesRep or wherever the many to one relationship points to TableBudget and not on Security_Access.
You can change your RLS rule to filter DimSalesRep instead using a relationship-based lookup
Create a calculated table
DimSalesRep[Sales Rep ID] IN CALCULATETABLE(
VALUES(Security_Access[Sales Rep ID]), Security_Access[Dashboard Manager Email] = USERPRINCIPALNAME())
This way the filter is applied on DimSalesRep which sits directly on one side of the one to many relationship into TableBudget so it propagates downside
O you can flip the relationship cross-filter direction between DimSalesRep and Security_Access to Both then you still need the rule to filter DimSalesRep and not the Security_Access as Security_Access is not upstream of budget data
5 Replies
- Murtaza_Ghafoor
Super User
Msampedro
If you are looking for endorsement, your approach looks alright but make sure
that the key is that your Security Table should contain one row per User × Sales Rep they are allowed to see.Note:
Don't create separate RLS rules for Director, Manager, Sales Rep, etc.Instead, put the complete access mapping in the Security Table:If this helps, ✓ Mark as Kudos | Help Other
- krishnakanth240
Super User
Hi Msampedro
RLS filter needs to sit on DimSalesRep or wherever the many to one relationship points to TableBudget and not on Security_Access.
You can change your RLS rule to filter DimSalesRep instead using a relationship-based lookup
Create a calculated table
DimSalesRep[Sales Rep ID] IN CALCULATETABLE(
VALUES(Security_Access[Sales Rep ID]), Security_Access[Dashboard Manager Email] = USERPRINCIPALNAME())
This way the filter is applied on DimSalesRep which sits directly on one side of the one to many relationship into TableBudget so it propagates downside
O you can flip the relationship cross-filter direction between DimSalesRep and Security_Access to Both then you still need the rule to filter DimSalesRep and not the Security_Access as Security_Access is not upstream of budget data
- m4ni2020New Member
If you are looking for validation then that setup should work.
USERPRINCIPALNAME() should work for this.
This will identify the logged-in user and filter the Security Access table to their email. The Rep IDs associated with that user can then filter the Sales Rep and Budget tables.
So, for example, if the Director's email appears against Rep IDs 1, 2, 3 and 4 in the Security Access table, they will see all four reps, while Manager 1 will only see the Rep IDs assigned to them.
Just make sure the email/UPN in the table matches the value returned by USERPRINCIPALNAME().
- ChrismarkSaberNew Member
Hi Msampedro,
There's a bit of conflicting advice in this thread, so worth being precise about why your original setup wasn't working — krishnakanth240's diagnosis is the right one, worth explaining the "why" behind it.
RLS filters only propagate in the direction of the relationship, from the "one" side to the "many" side. In your model, DimSalesRep is the one-side hub, with both Security_Access and Budget hanging off it as separate many-side tables. That makes Security_Access and Budget siblings, not parent/child — filtering rows directly in Security_Access has no effect on Budget, because nothing in your model is actually filtered by Security_Access. That's why the rule looked reasonable but didn't restrict anything.
The fix is to put the RLS rule on DimSalesRep itself, using CALCULATETABLE to look up the allowed Sales Rep IDs from Security_Access without relying on a relationship to do it:
DimSalesRep[Sales Rep ID] IN CALCULATETABLE(VALUES(Security_Access[Sales Rep ID]), Security_Access[Dashboard Manager Email] = USERPRINCIPALNAME())
Because DimSalesRep is genuinely upstream of Budget (one-to-many), a filter placed there correctly cascades down into every Budget row.
On the many-to-many approach suggested further down: it can technically work, but for sales budget/comp data specifically, I'd avoid it if you can. Many-to-many plus bidirectional cross-filtering makes it much harder to audit exactly who can see what, and RLS bugs on comp-adjacent data are the kind of mistake you really don't want to discover after the fact. The CALCULATETABLE approach above keeps the logic explicit and easy to verify.
One suggestion regardless of which approach you land on: before shipping this, use "View as Roles" in Desktop to actually impersonate each Manager/Director/Rep persona and confirm they see exactly the rows they should — cheap insurance on something this sensitive.
- Natarajan_M
Super User
Hi Msampedro ,
Based on the use case that you shared I think we can have one security table to drive the RLS and it need to join to the dim sales rep on many to many and the security table filter the dim sales rep.
model:
Sales rep01
Manager :
Director :
Data:
Please find the attached pbix file for more details : RLS Sample.pbixThanks
Natarajan Manivasagan
If you found this helpful, please consider giving it a Kudos and marking it as the accepted solution — it goes a long way in helping others facing the same issue.
AI-assisted drafting: AI was used to help structure and phrase this response. I reviewed and validated the technical content before posting.🏆Best Solution for Enterprise BI — 2026 Microsoft Fabric Semantic Link Developer Experience Challenge
👉Microsoft announcement · View the winning notebookFor more Power BI tips and discussions, let's connect on LinkedIn.
Cheers!