Populering av aggregater når de opprettes

48 views
Skip to first unread message

Ellen Lippe

unread,
Sep 2, 2015, 5:22:50 AM9/2/15
to DDD Sverige
Hei

Jeg har et spørsmål rundt aggregater og lesing/skriving til database.

Når jeg jobber med DDD liker jeg å alltid lese opp hele aggregater, med hele objektgrafen populert, slik at jeg alltid vet at jeg har "alt" og kan spørre aggregatet om hva jeg vil. Jeg har vært borti kode hvor man leser opp forskjellige deler av aggregatet i forskjellige metoder, og får da typisk kode som sier "if aggregate.something is null, then load something from database (based on id). Then do aggregate.SomeOperationDependentOnSomething), som jeg ikke syns så mye om.

Men hvordan gjør man det best når et aggregat "oppstår". F.eks, har vi i vårt system brukere som kan ha ulike roller. En rolle er knyttet til en gruppe som igjen er knyttet til ett sett privilegier. Så utifra hvilken rolle en bruker har, kan man også vite hvilke privilegier denne brukeren har. Vi bruker EntityFramework, så domeneobjektene våre har typisk bade id som referanse OG en virtual property til samme objekt. (Et mønster jeg ikke liker i det hele tatt, men det er mye jeg ikke liker med EF og det blir vel en helt annen diskusjon..)

Det som skjer nå når man legger til en ny bruker til systemet, er at brukeren opprettes med kun en id til rollen. Så lagres brukeren med rolle-id. Neste gang brukeren leses opp vil hele rolle-grafen være populert, og man kan spørre brukeren hvilke privilegier han har. Men FØR brukeren er lagret, har han altså ikke denne informasjonen. Dvs aggregatet ser ulikt ut før og etter lagring.

Hvordan gjør man dette på en god mate? Er det f.eks vanlig å lese opp hele rollen med alle under-objektene, slik at man kan legge denne til brukeren før den lagres? Andre tanker?

- Ellen Lippe

Michael Bergman

unread,
Oct 8, 2015, 3:57:20 PM10/8/15
to DDD Sverige
Hej Ellen,

Jag håller med dig om att en ”aggregate root entity” alltid ska läsas upp respektive sparas i sin helhet. På detta sätt undviks bland annat if-null-kontroller i koden.

Ibland, när data bara ska användas i lässyfte, kan det bli för dålig prestanda att läsa upp en hel ”aggregate”-graf. Då brukar vi istället skapa en ny klass som bara innehåller den data som efterfrågas. Har man mycket läsbehov av olika karaktär kan man överväga CQRS.

Du bör enbart ha navigation-properties som refererar inom en ”aggregate”. För referenser utanför ”aggregate” används helst endast nycklar, t.ex. RolleId. Vad jag känner till kräver dessvärre EF att det måste finnas en navigation-property för att kunna definiera en association i t.ex. Code-First. Vi har därför valt att inte låta EF känna till alls hur t.ex. RolleId är associerad. Istället skapar vi upp foreign key constraints till databasen i ett separat script.

Det låter som ni valt att Bruker, Rolle, Gruppe och Privilegie samtliga är egna ”aggregate root entity”. Kanske skulle ni överväga om några av dessa lämpar sig bättre som ”value object”. Ofta blir det lättare att spara en ”aggregate root entity” som innehåller ”value object” istället för upprätthålla referenser. I annat fall låter det kanske som för mycket ansvar att fråga en Bruker vilka Privilegier denne har. Kanske bättre att skapa en ”application service” som kan ansvara för att sätta privilegier för ett visst BrukerId eller svara på vilka denne bruker redan har.

/Michael
Reply all
Reply to author
Forward
0 new messages