Inactieve relaties in een Power BI-model zijn waarschijnlijk door iedereen tegengekomen die zijn eerste stappen in Power BI heeft gezet. Omdat er maar één actief pad tussen twee tabellen in een model kan zijn, resulteert het koppelen van alles wat verwant lijkt (zoals de meeste beginners in Power BI doen) eerder vroeg dan laat in […]
Inactieve relaties in een Power BI-model zijn waarschijnlijk door iedereen tegengekomen die zijn eerste stappen in Power BI heeft gezet. Omdat er maar één actief pad tussen twee tabellen in een model kan zijn, resulteert het koppelen van alles wat verwant lijkt (zoals de meeste beginners in Power BI doen) eerder vroeg dan laat in ‘stippellijnen’. Het is duidelijk dat er een goede datamodellering nodig is, waarbij we van inactieve relaties die ‘per ongeluk’ zijn ontstaan, moeten overgaan naar relaties die voor specifieke doeleinden zijn ontworpen.
Een typisch gebruik van inactieve relaties is het koppelen van feiten aan verschillende data. Op deze manier kan een verkooptransactie gerapporteerd worden op b.v. besteldatum om inkomsten te analyseren, of op betalingsdatum om betalingen en cashflow te analyseren:
Een inactieve relatie kan worden geactiveerd in het kader van een DAX-berekening met behulp van de USERELATIONSHIP DAX-functie in combinatie met CALCULATE:
USERELATIONSHIP activeert de inactieve relatie, waardoor andere relaties effectief worden geïnactiveerd.
Dit alles is prima te doen in een Power BI-model. Er zijn echter enkele zaken waarmee u rekening moet houden wanneer u beveiliging aan een model toevoegt. Het gebruik van inactieve relaties in combinatie met beveiliging op rijniveau kan leiden tot fouten die enigszins onverwacht kunnen zijn, maar die wel logisch zijn als je erover nadenkt.
Laten we het onderstaande modeldiagram bekijken.
De feiten in dit model registreren de gewerkte uren van werknemers van een bedrijf. Het blijkt dat de meeste gewerkte uren aan projecten worden besteed. Dit kunnen projecten zijn die door klanten worden betaald of projecten die anderszins als productief worden beschouwd; dit worden directe uren genoemd. Maar medewerkers besteden ook tijd aan niet-projectgerelateerde werkzaamheden, zoals interne vergaderingen; of met ziekteverlof bent. Dit worden indirecte uren genoemd.
Projecten hebben projectmanagers en we willen informatie kunnen opvragen over het totale aantal uren dat aan projecten is besteed, maar ook geaggregeerd per projectmanager. Als we bijvoorbeeld Anna selecteren, kunnen we de hoeveelheid tijd berekenen die wordt besteed aan de projecten die Anna beheert, of de indirecte uren voor Anna zelf. De DAX-berekeningen om dit te doen, zijn vrij eenvoudig met USERELATIONSHIP:
Laten we nu beveiliging aan dit model toevoegen. Het is immers logisch dat Anna haar eigen indirecte uren en uren die aan haar projecten zijn besteed, kan zien, maar niet noodzakelijkerwijs de indirecte uren van mensen die aan haar projecten werken. Om te testen kunnen we een eenvoudige DAX-beveiligingsexpressie toevoegen die statische beveiliging alleen voor Anna implementeert, waardoor de toegang tot de tabel Werknemers wordt beperkt tot alleen de rij van Anna:
Beveiliging op rijniveau kan in dit model zonder problemen worden ingesteld. Alleen wanneer de inactieve relatie wordt geactiveerd door de meting Uren (indirect) in een rapport te gebruiken, wordt er echter een fout gegenereerd:
Wat is er gebeurd? De foutmelding geeft aan dat we nu twee actieve paden tussen twee tabellen hebben. Hoewel USERELATIONSHIP normaal gesproken een bestaande, actieve relatie inactiveert, zorgt het instellen van beveiliging op rijniveau ervoor dat de actieve relatie niet inactief wordt.
Hoewel dit in eerste instantie misschien vreemd klinkt, is het volkomen logisch. Of laten we dit heel duidelijk maken: dit is precies wat je wilt! Als we een beveiligingsfilter effectief kunnen uitschakelen door het kruisfiltergedrag van relaties te veranderen, zou beveiliging nutteloos worden. Zeker als je beseft dat gebruikers van een Power BI-model nieuwe metingen in een rapport kunnen toevoegen zonder dat ze het model zelf hoeven te bewerken.
Hoe dan ook, de conclusie hier is dat je heel voorzichtig moet zijn bij het gebruik van inactieve relaties in combinatie met beveiliging op rijniveau. Maar wat is de juiste manier om dit te doen? Er zijn twee opties die ik kan bedenken.
De eerste is om RLS niet in de filtertabel Werknemer te implementeren, maar in de feitentabel fHours. Dit vereist een iets complexer DAX-beveiligingsfilter op fHours; bovendien beveiligt het niet de tabel Werknemers, noch de tabel Project.
De tweede optie, en waarschijnlijk de betere, is om de fHours-feitentabel in tweeën te splitsen: één voor directe uren en één voor indirecte uren. Dit elimineert de noodzaak van een inactieve relatie en maakt het mogelijk om aangepaste beveiligingslogica op beide tabbladen toe te passen