Forum Discussion

Msampedro's avatar
Msampedro
Icon for Advocate I rankAdvocate I
1 month ago
Solved

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

  • 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





     

  • 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

  • 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().

  • 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.

  • 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.pbix


    Thanks 
    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 notebook

    For more Power BI tips and discussions, let's connect on LinkedIn.

    Cheers!