DDD i java: AnvÀnda EntityManager för att skapa ID i IdentityFactory

38 views
Skip to first unread message

Jonas Andersson

unread,
Nov 2, 2010, 10:41:52 AM11/2/10
to dddsv...@googlegroups.com

Hej!

TÀnkte fÄ lite synpunkter pÄ att anvÀnda entitymanager frÄn factory för att skapa en identity. (Hittade ingen factory som gör detta i DDDSample)

Mitt resonemang gÄr ungefÀr sÄhÀr:

En identity jÀmförs uteslutande pÄ ID, det Àr en del av att vara valid.
DÀrför mÄste factory:n som skapar identity:n sÀtta ID.

I praktiken vill man generera ID frÄn databas, och alltsÄ vill jag anvÀnda EntityManagern för att generera ID.

Man fÄr kod som ser ut ungefÀr sÄhÀr:

public class OrderFactory {

@PersistenceContext
private EntityManager em;

public Order createOrder() throws Exception {
return new Order(getNextOrderId());
}

Long getNextOrderId() {
OrderIdCounter orderIdCounter = new OrderIdCounter();
return em.merge(orderIdCounter).getOrderId();
}
}


Men det finns nÄgra kritiska röster:

- Vi har ingen garanti för att orderId faktiskt anvÀnds (att motsvarande order persisteras), vilket skapar hÄl i orderid-sekvensen, vilket stör administratörer (Men det kan vi egentligen aldrig garantera)
- Persistens-kod hamnar pÄ tvÄ olika stÀllen, OrderFactory och OrderRepository.


Vad tycker ni, Àr detta en ultimat lösning eller finns det nÄgot snyggare sÀtt?

-- Jonas

Jonas Andersson

unread,
Nov 2, 2010, 11:13:28 AM11/2/10
to dddsv...@googlegroups.com

Jag anvÀnde identity ist.f. entity insÄg jag just, rÀttat nedan:


Hej!

TÀnkte fÄ lite synpunkter pÄ att anvÀnda entitymanager frÄn factory för att skapa en entity. (Hittade ingen factory som gör detta i DDDSample)

Mitt resonemang gÄr ungefÀr sÄhÀr:

En entity jÀmförs uteslutande pÄ ID, det Àr en del av att vara valid.
DÀrför mÄste factory:n som skapar entity:n sÀtta ID.

Rickard Öberg

unread,
Nov 2, 2010, 9:07:49 PM11/2/10
to dddsv...@googlegroups.com
On 2010-11-02 22.41, Jonas Andersson wrote:
> En identity jïżœmfïżœrs uteslutande pïżœ ID, det ïżœr en del av att vara valid.
> Dïżœrfïżœr mïżœste factory:n som skapar identity:n sïżœtta ID.

Det beror pïżœ vilka patterns man anvïżœnder. Exempelvis om du anvïżœnder
EventSourcing sïżœ mïżœste id't genereras av kommandot och anvïżœndas som
input till eventet, som i sin tur skapar entity med det id't. Annars
funkar inte replay.

> I praktiken vill man generera ID frïżœn databas, och alltsïżœ vill jag
> anvïżœnda EntityManagern fïżœr att generera ID.

I praktiken har jag alltid anvïżœnt en UUID generator. Se ovan. Och jag
skiljer mellan id'n fïżœr datanbaser och fïżœr mïżœnniskor. Exempelvis
order-id ïżœr fïżœr mïżœnniskor, och kan dïżœrfïżœr sïżœttas nïżœr ordern ïżœr bekrïżœftad
-> inga hïżœl i sekvensen. Funkar finfint.

> - Vi har ingen garanti fïżœr att orderId faktiskt anvïżœnds (att motsvarande
> order persisteras), vilket skapar hïżœl i orderid-sekvensen, vilket stïżœr
> administratïżœrer (Men det kan vi egentligen aldrig garantera)

Se ovan!

> - Persistens-kod hamnar pïżœ tvïżœ olika stïżœllen, OrderFactory och
> OrderRepository.

OrderFactory och OrderRepository ïżœr vïżœl interface, sïżœ borde kunna
implementeras av samma objekt?

/Rickard

Dan Bergh Johnsson

unread,
Nov 3, 2010, 4:10:28 PM11/3/10
to dddsv...@googlegroups.com

>
> Och jag skiljer mellan id'n för datanbaser och för mÀnniskor.

InstÀmmer, jag försöker undvika att ge tekniska konstruktioner
domÀnlogisk mening.

> Exempelvis order-id Àr för mÀnniskor, och kan dÀrför sÀttas
> nÀr ordern Àr bekrÀftad -> inga hÄl i sekvensen. Funkar finfint.
>
>> - Persistens-kod hamnar pÄ tvÄ olika stÀllen, OrderFactory och
>> OrderRepository.
>
> OrderFactory och OrderRepository Àr vÀl interface, sÄ borde kunna
> implementeras av samma objekt?

Ja, och interfacen kan ligga i paket xyz.domain medan implementationen
ligger i xyz.infrastructure.sqldb el likn. SĂ„ blir xyz.domain helt
fritt frÄn referenser till specifik infrastruktur och kan t ex
enhetstestas utan annat pÄ classpath.

Dan


> /Rickard
>
> --
> Det hÀr meddelandet skickas till dig eftersom du prenumererar pÄ gru
> ppen DDD Sverige i Google Groups.
> Om du vill göra ett inlÀgg i den hÀr gruppen skickar du e-post till dddsverige@googlegroups.
> com.
> Om du vill sluta prenumerera pÄ den hÀr gruppen skickar du e-post ti
> ll dddsverige+...@googlegroups.com.
> För fler alternativ, besök gruppen pÄ http://groups.google.com/group/dddsverige?hl
> =sv.
>

Niclas Nilsson

unread,
Nov 3, 2010, 5:14:14 PM11/3/10
to dddsv...@googlegroups.com
On 3 nov 2010, at 21.10, Dan Bergh Johnsson wrote:

> Ja, och interfacen kan ligga i paket xyz.domain medan implementationen ligger i xyz.infrastructure.sqldb el likn. SÄ blir xyz.domain helt fritt frÄn referenser till specifik infrastruktur och kan t ex enhetstestas utan annat pÄ classpath.

Va? Enhetstestar du interfacet? ;-)

Mvh
Niclas

Dan Bergh Johnsson

unread,
Nov 4, 2010, 2:50:30 AM11/4/10
to dddsv...@googlegroups.com, dddsv...@googlegroups.com

Visserligen dokumenterar jag gÀrna interfacet med enhetstester, men
det var inte riktigt det jag hade i Ätanke.

Jag tÀnkte frÀmst pÄ att andra klasser som har beroenden till fabrik
och repository inte behöver nÄgra utÄtgÄende beroenden som i sin
tur sprider sig till en massa andra paket. IstÀllet blir domÀnpaketet
sjÀlvinnehÄllande.

Dan
>

Magnus Heino

unread,
Nov 4, 2010, 3:09:12 AM11/4/10
to dddsv...@googlegroups.com


Ja, och interfacen kan ligga i paket xyz.domain medan implementationen ligger i xyz.infrastructure.sqldb el likn. SÄ blir xyz.domain helt fritt frÄn referenser till specifik infrastruktur och kan t ex enhetstestas utan annat pÄ classpath.

Va? Enhetstestar du interfacet? ;-)
Visserligen dokumenterar jag gÀrna interfacet med enhetstester, men det var inte riktigt det jag hade i Ätanke.

Jag tÀnkte frÀmst pÄ att andra klasser som har beroenden till fabrik och repository inte behöver nÄgra utÄtgÄende beroenden som i sin tur sprider sig till en massa andra paket. IstÀllet blir domÀnpaketet sjÀlvinnehÄllande.

FrÄn sjÀlvinnehÄllande sÄ glider jag raskt över till sjÀlvbeskrivande. 

Jag vet inte vad du hade för tanke bakom xyz.domain och xyz.infrastructure.sqldb ovan, men Àr det nÄgon som har idéer, referensprojekt, böcker, bloggar vÀrda att sprida som diskuterar namngivning av paket, och dÄ Àven gÀrna har en tanke kring struktur och beroden typ http://www.headwaysoftware.com/images/snag02.jpg ? 

Det finns de facto-standarder inom det mycket, mappstrukturer om man kör maven, namngivning av klasser baserat pÄ patterns etc, men just paketnamn kÀnns som ett bortglömt Àmne. VÀldigt mÄnga system har ju lite web, databas, meddlandehantering etc, men hur det Àr strukturerat skiljer oftast stort. Och tittar man pÄ exempelprojekt frÄn ramverk eller liknande sÄ Àr paketnamngivning oftast helt bortglömt... trist tycker jag.

--

  /Magnus Heino

Dan Bergh Johnsson

unread,
Nov 4, 2010, 3:38:17 AM11/4/10
to dddsv...@googlegroups.com
PÄ JavaZone var jag pÄ en blixtpresentation med Filip van Laenen som berörde detta. NÀmnde det pÄ http://blog.omegapoint.se/2010/09/javazone-oslo-onsdag-8-september-2010.html

Filips poÀng var att hierarkiska paketstrukturer Àr ganska 1900-talsmÀssigt mossiga. SÀttet vi gör pÄ 2000-talet Àr givetvis att sÀtta taggar. 

Varför inte? Tidigare exempel kanske skulle taggars med "domain" "entity" "factory" t ex. 

   Dan
--
Det hÀr meddelandet skickas till dig eftersom du prenumererar pÄ gruppen DDD Sverige i Google Groups.
Om du vill göra ett inlÀgg i den hÀr gruppen skickar du e-post till dddsv...@googlegroups.com.
Om du vill sluta prenumerera pÄ den hÀr gruppen skickar du e-post till dddsverige+...@googlegroups.com.

Jonas Andersson

unread,
Nov 4, 2010, 5:13:33 AM11/4/10
to dddsv...@googlegroups.com



I praktiken har jag alltid anvÀnt en UUID generator. Se ovan. Och jag skiljer mellan id'n för datanbaser och för mÀnniskor. Exempelvis order-id Àr för mÀnniskor, och kan dÀrför sÀttas nÀr ordern Àr bekrÀftad -> inga hÄl i sekvensen. Funkar finfint.


Det kĂ€nns inte riktigt rĂ€tt för mig, en orders identet bestĂ€ms ju dĂ„ inte lĂ€ngre av orderid, vilket jag tycker att den borde (Å andra sidan Ă€r jag fortfarande jag, oavsett vad mitt personnr Ă€r). MĂ„ste fundera mer pĂ„ det. Instinktivt ogillar jag ocksĂ„ att en Entity innehĂ„ller saker av "rent teknisk" natur, vilket ju UUID blir - Ordern blir inte lika "ren". Men det löser onekligen upp beroendet mellan Factory och EntityManager.
 

- Persistens-kod hamnar pÄ tvÄ olika stÀllen, OrderFactory och
OrderRepository.

OrderFactory och OrderRepository Àr vÀl interface, sÄ borde kunna implementeras av samma objekt?


Sant!

Tack för svar, jag har fÄtt en del aha-tankar! :)

-- Jonas

Rickard Öberg

unread,
Nov 4, 2010, 6:00:27 AM11/4/10
to dddsv...@googlegroups.com
On 2010-11-04 17.13, Jonas Andersson wrote:
> Det kïżœnns inte riktigt rïżœtt fïżœr mig, en orders identet bestïżœms ju dïżœ
> inte lïżœngre av orderid, vilket jag tycker att den borde (ïżœ andra sidan
> ïżœr jag fortfarande jag, oavsett vad mitt personnr ïżœr). Mïżœste fundera mer
> pïżœ det. Instinktivt ogillar jag ocksïżœ att en Entity innehïżœller saker av

> "rent teknisk" natur, vilket ju UUID blir - Ordern blir inte lika "ren".
> Men det lïżœser onekligen upp beroendet mellan Factory och EntityManager.

I mina system har ALLA entities ALLTID ett UUID som identitet, ur ett
tekniskt perspektiv. Sedan har vi "ïżœrendeid" (vi gïżœr Case Management),
personnr, och lite annat fïżœr sïżœkning och presentation, men det ïżœr HELT
andra usecase.

/RIckard

Dan Bergh Johnsson

unread,
Nov 4, 2010, 9:00:49 AM11/4/10
to dddsv...@googlegroups.com

4 nov 2010 kl. 10.13 skrev Jonas Andersson <jona...@gmail.com>:

> I praktiken har jag alltid anvÀnt en UUID generator. Se ovan. Och ja
> g skiljer mellan id'n för datanbaser och för mÀnniskor. Exempelvis
> order-id Àr för mÀnniskor, och kan dÀrför sÀttas nÀr ordern
> Àr bekrÀftad
>
>

> Det kÀnns inte riktigt rÀtt för mig, en orders identet bestÀms ju
> dĂ„ inte lĂ€ngre av orderid, vilket jag tycker att den borde (Å
> andra sidan Àr jag fortfarande jag, oavsett vad mitt personnr Àr). M
> Äste fundera mer pÄ det.

Jag brukar tÀnka pÄ det som att orderid Àr ett verksamhetsattribut,
vilket som helst. Sedan finns det attribut eller kombinationer av
attribut som unikt pekar ut (högst) en entitet - i vissa .NET-kretsar
har jag hört sÄdana uppsÀttningar kallas "determinanter".

> Instinktivt ogillar jag ocksÄ att en Entity innehÄller saker av "ren
> t teknisk" natur, vilket ju UUID blir - Ordern blir inte lika "ren".
> Men det löser onekligen upp beroendet mellan Factory och EntityMana
> ger.

Egentligen Àt uuid bara ett implementationstrick. TÀnk att vi hade en
oÀndlig minnes-heap pÄ en krashsÀker dator som aldrig behövde
startas om. DĂ„ skulle varje objekt identifieras av den minnesadress
den lÄg pÄ och inga uuid skulle behövas. DÀremot skulle en order
fortfarande ha sitt verksamhetsmÀssiga orderid.

Nu har vi ingen sÄdan heap utan mÄste spara ner vÄra objekt i
diverse persistensmekanismer. DÄ Àr uuid bara ett trick för att
spara och Äterskapa objektet - egentligen bara en "minnesadress" i det
oÀndliga persistensminnet.

NÀr jag tÀnker pÄ det sÀttet kÀnns det inte sÄ stötande att det
finns ett "tekniskt" attribut i en entitetsimplementation. Åtminstone
inte mer stötande Àn att en service av tekniska skÀl skulle kunna
hÄlla en Connection eller Socket öppen under lite lÀngre tid.

Dan

Patrik Fredriksson

unread,
Nov 4, 2010, 3:23:02 PM11/4/10
to dddsv...@googlegroups.com
Hej!

Exemplet med personnummer Àr bra (och om jag inte minns fel anvÀnds
det av Fowler i PoEAA runt precis detta resonemang).

Att det finns en identitet i domÀnen, hÀr orderid, Àr en dessutom en
viktig observation, dÄ det ger tydlig hjÀlp i att sortera ut
entiteterna frÄn vÀrdeobjekten.

/Patrik

2010/11/4 Dan Bergh Johnsson <dan.bergh...@gmail.com>:


>
>
> 4 nov 2010 kl. 10.13 skrev Jonas Andersson <jona...@gmail.com>:
>
>> I praktiken har jag alltid anvÀnt en UUID generator. Se ovan. Och jag
>> skiljer mellan id'n för datanbaser och för mÀnniskor. Exempelvis order-id Àr
>> för mÀnniskor, och kan dÀrför sÀttas nÀr ordern Àr bekrÀftad
>>
>>
>> Det kÀnns inte riktigt rÀtt för mig, en orders identet bestÀms ju dÄ inte
>> lĂ€ngre av orderid, vilket jag tycker att den borde (Å andra sidan Ă€r jag

>> fortfarande jag, oavsett vad mitt personnr Àr). MÄste fundera mer pÄ det.


>
> Jag brukar tÀnka pÄ det som att orderid Àr ett verksamhetsattribut, vilket
> som helst. Sedan finns det attribut eller kombinationer av attribut som
> unikt pekar ut (högst) en entitet - i vissa .NET-kretsar har jag hört sÄdana
> uppsÀttningar kallas "determinanter".
>
>> Instinktivt ogillar jag ocksÄ att en Entity innehÄller saker av "rent
>> teknisk" natur, vilket ju UUID blir - Ordern blir inte lika "ren". Men det
>> löser onekligen upp beroendet mellan Factory och EntityManager.
>
> Egentligen Àt uuid bara ett implementationstrick. TÀnk att vi hade en
> oÀndlig minnes-heap pÄ en krashsÀker dator som aldrig behövde startas om. DÄ
> skulle varje objekt identifieras av den minnesadress den lÄg pÄ och inga
> uuid skulle behövas. DÀremot skulle en order fortfarande ha sitt
> verksamhetsmÀssiga orderid.
>
> Nu har vi ingen sÄdan heap utan mÄste spara ner vÄra objekt i diverse
> persistensmekanismer. DÄ Àr uuid bara ett trick för att spara och Äterskapa
> objektet - egentligen bara en "minnesadress" i det oÀndliga
> persistensminnet.
>
> NÀr jag tÀnker pÄ det sÀttet kÀnns det inte sÄ stötande att det finns ett
> "tekniskt" attribut i en entitetsimplementation. Åtminstone inte mer
> stötande Àn att en service av tekniska skÀl skulle kunna hÄlla en Connection
> eller Socket öppen under lite lÀngre tid.
>
>   Dan
>

Dan Bergh Johnsson

unread,
Nov 4, 2010, 5:24:15 PM11/4/10
to dddsv...@googlegroups.com, dddsv...@googlegroups.com
Sitter just nu med en domÀn dÀr "byta personnummer" Àr en naturlig
hÀndelse, kanske till och med normalfallet. Gissa om det blir lite
trixigt nÀr den enda nyckel som finns att tillgÄ (av arki-historiska
skÀl) Àr just personnummer.

Dan

4 nov 2010 kl. 20.23 skrev Patrik Fredriksson <patrik.fr...@citerus.se
>:

> Om du vill göra ett inlÀgg i den hÀr gruppen skickar du e-post till dddsverige@googlegroups.

> com.
> Om du vill sluta prenumerera pÄ den hÀr gruppen skickar du e-post ti

> ll dddsverige+...@googlegroups.com.

Mikael Egnér

unread,
Nov 4, 2010, 6:21:17 PM11/4/10
to dddsv...@googlegroups.com
I Sharp Architecture (ramverk för .Net) sÀtter man ett attribut "Domain Signature" pÄ de properties som unikt identifierar ett objekt verksamhetsmÀssigt.

Alla egna entititesklasser Àrver frÄn basklassen Entity som har överlagrar funktionerna Equals och GetHashCode (dessa funktioner Àr viktiga för NHibernate (som Àr OR-ramverket som som Sharp Architecture anvÀnder)
Equals och GetHashCode baseras pÄ de properties som Àr markerade med "Domain Signature" attributet

Entity-klassen innehÄller ocksÄ propertyn Id som Àr en integer och Àr objektets tekniska id.
(Om man behöver jobba med annat Àn integer som teknisk nyckel finns en annan klass att Àrva ifrÄn)

Exempel pÄ anvÀndning
PÄ klassen Person sÀtter man DomainSignature-attributet pÄ personnummer propertyn

Detta gör att du kan skriva personA.Equals(personB) och fÄ svaret true om instanserna har samma personnummer.

För valueobjects finns basklassen ValueObject dÀr du du inte kan sÀtta DomainSignature eftersom alla egenskaper pÄ ett sÄdant objekt avgör om det Àr likadant som ett annat

/Mikael Egnér


-----Ursprungligt meddelande-----
FrÄn: dddsv...@googlegroups.com [mailto:dddsv...@googlegroups.com] För Dan Bergh Johnsson
Skickat: den 4 november 2010 22:24
Till: dddsv...@googlegroups.com
Kopia: dddsv...@googlegroups.com
Ämne: Re: DDD i java: AnvĂ€nda EntityManager för att skapa ID i IdentityFactory

Dan

--
Det hÀr meddelandet skickas till dig eftersom du prenumererar pÄ gruppen DDD Sverige i Google Groups.
Om du vill göra ett inlÀgg i den hÀr gruppen skickar du e-post till dddsv...@googlegroups.com.

Rickard Öberg

unread,
Nov 4, 2010, 9:08:25 PM11/4/10
to dddsv...@googlegroups.com
On 2010-11-05 06.21, Mikael Egnïżœr wrote:
> I Sharp Architecture (ramverk fïżœr .Net) sïżœtter man ett attribut
> "Domain Signature" pïżœ de properties som unikt identifierar ett objekt
> verksamhetsmïżœssigt.
>
> Alla egna entititesklasser ïżœrver frïżœn basklassen Entity som har
> ïżœverlagrar funktionerna Equals och GetHashCode (dessa funktioner ïżœr
> viktiga fïżœr NHibernate (som ïżœr OR-ramverket som som Sharp
> Architecture anvïżœnder) Equals och GetHashCode baseras pïżœ de
> properties som ïżœr markerade med "Domain Signature" attributet
>
> Entity-klassen innehïżœller ocksïżœ propertyn Id som ïżœr en integer och ïżœr
> objektets tekniska id. (Om man behïżœver jobba med annat ïżœn integer som
> teknisk nyckel finns en annan klass att ïżœrva ifrïżœn)
>
> Exempel pïżœ anvïżœndning Pïżœ klassen Person sïżœtter man
> DomainSignature-attributet pïżœ personnummer propertyn
>
> Detta gïżœr att du kan skriva personA.Equals(personB) och fïżœ svaret

> true om instanserna har samma personnummer.

Detta verkar gïżœra antagandet att tvïżœ entiteter som ïżœr domïżœn-mïżœssigt
identiska har olika tekniska id'n. Korrekt? Hur kan det komma sig att
det finns tvïżœ entiteter som representerar samma domïżœnobjekt? Varfïżœr inte
bara jïżœmfïżœra pïżœ id't?

/Rickard

Mikael Egnér

unread,
Nov 5, 2010, 3:02:41 AM11/5/10
to DDD Sverige
Korrekt nja...
Det tekniska id:t skapas oftast(lÀs alltid) först nÀr objektet sparas
i databasen
Med DomainSignature attributet fÄr du "automatisk" validering av att
det inte sparas tvÄ objekt som domÀnmÀssigt Àr identiska.
Tanken Àr att ramverket skall förenkla och tydliggöra och du slipper
skriva egen valideringskod för att t ex validera att inte tvÄ personer
sparas med samma personnummer.

Mer info (och tydligare Àn vad jag lyckas med) finns hÀr:
http://nhforge.org/wikis/patternsandpractices/identity-field-equality-and-hash-code.aspx
och hÀr.
http://wiki.sharparchitecture.net/(S(if1dxr45yunexj3fu33ekmrr))/Tutorial2DevDomainModel.ashx

/Mikael
> /Rickard- Dölj citerad text -
>
> - Visa citerad text -

Dan Bergh Johnsson

unread,
Nov 5, 2010, 3:06:44 AM11/5/10
to dddsv...@googlegroups.com
Utan att veta detaljerna i Sharp antar jag att det tar höjd för att
ett objekt (entitet) har varit "detached", valsat runt pÄ nÄgon
klient och kommit tillbaka med potentiellt förÀndrade vÀrden. I det
lÀget Àr inte de tvÄ objekten "utbytbara" mot varandra lÀngre.
Förmodar att NHibernate anvÀnder detta för att avgöra om det finns
Àndringar att merga ihop inför persistens.

Dan

5 nov 2010 kl. 02.08 skrev Rickard Öberg <rickar...@gmail.com>:

> On 2010-11-05 06.21, Mikael Egnér wrote:
>> I Sharp Architecture (ramverk för .Net) sÀtter man ett attribut
>> "Domain Signature" pÄ de properties som unikt identifierar ett obj
>> ekt


>> verksamhetsmÀssigt.
>>
>> Alla egna entititesklasser Àrver frÄn basklassen Entity som har
>> överlagrar funktionerna Equals och GetHashCode (dessa funktioner Àr

>> viktiga för NHibernate (som Àr OR-ramverket som som Sharp


>> Architecture anvÀnder) Equals och GetHashCode baseras pÄ de
>> properties som Àr markerade med "Domain Signature" attributet
>>
>> Entity-klassen innehÄller ocksÄ propertyn Id som Àr en integer och
>> Àr

>> objektets tekniska id. (Om man behöver jobba med annat Àn integer
>> som


>> teknisk nyckel finns en annan klass att Àrva ifrÄn)
>>
>> Exempel pÄ anvÀndning PÄ klassen Person sÀtter man
>> DomainSignature-attributet pÄ personnummer propertyn
>>

>> Detta gör att du kan skriva personA.Equals(personB) och fÄ svaret


>> true om instanserna har samma personnummer.
>

> Detta verkar göra antagandet att tvÄ entiteter som Àr domÀn-
> mÀssigt identiska har olika tekniska id'n. Korrekt? Hur kan det komm
> a sig att det finns tvÄ entiteter som representerar samma domÀnobjek
> t? Varför inte bara jÀmföra pÄ id't?
>
> /Rickard

Torbjörn Kalin

unread,
Nov 5, 2010, 5:59:21 AM11/5/10
to DDD Sverige
Det hÀr Àr nÄgot som jag tycker Àr lÀskigt bÄde med hur
SharpArchitecture löst det och med hur ad-hoc-lösningen verkar se ut.

I SharpArchitecture Àr Equals() baserat pÄ Id:t om det finns (vaken
this eller other Àr transienta). Annars anvÀnds "objektsignaturen" som
Ă€r den naturliga nyckeln (typ personnummer) [1].

Ad-hoc-lösningen Àr vÀl annars att bara anvÀnda Id:t (eller?).

Om man anvÀnder generated Id:s Àndras alltsÄ objektets equals() nÀr
man skriver det till databasen. Detta kan skapa problem om man vill
lÀgga objekten t ex i ett Set (parent->child).

NÄgon som har nÄgra tankar kring detta?

/Torbjörn


[1] En diskussion kring varför SharpArchitecture valt att göra sÄ
finns beskrivet hÀr:
http://devlicio.us/blogs/billy_mccafferty/archive/2007/04/25/using-equals-gethashcode-effectively.aspx



On Nov 5, 8:02 am, Mikael Egnér <mikael.eg...@dotnetmentor.se> wrote:
> Korrekt nja...
> Det tekniska id:t skapas oftast(lÀs alltid) först nÀr objektet sparas
> i databasen
> Med DomainSignature attributet fÄr du "automatisk" validering av att
> det inte sparas tvÄ objekt som domÀnmÀssigt Àr identiska.
> Tanken Àr att ramverket skall förenkla och tydliggöra och du slipper
> skriva egen valideringskod för att t ex validera att inte tvÄ personer
> sparas med samma personnummer.
>
> Mer info (och tydligare Àn vad jag lyckas med) finns hÀr:http://nhforge.org/wikis/patternsandpractices/identity-field-equality...
> och hÀr.http://wiki.sharparchitecture.net/(S(if1dxr45yunexj3fu33ekmrr))/Tutor...

Mikael Egnér

unread,
Nov 5, 2010, 8:03:38 AM11/5/10
to DDD Sverige
Det symboliserar vÀl sÄ som det ofta Àr inom systemutveckling.
Det finns inget perfekt alternativ utan man fÄr vÀlja den bÀsta
kompromissen.

Ta exemplet med att lÀgga till personer i ett "Set" och tÀnker oss att
personnummer Àr det domÀnspecifika id:t.
Set Àr alltsÄ en Collection med endast unika poster i.
Traditionellt har man ihop med NHibernate oftast anvÀnt
Iesi.Collections.ISet, men numera sÄ finns det en "native"
implementation av set i .Net.
Om du skapar upp tvÄ personer med samma personnummer och lÀgger det i
ett "Set" sÄ kommer bara Set:et att returnera det först tillagda.

Testet nedan ger "grönt" (alla Asserts gÄr igenom)

/Mikael

public class Person : Entity
{
[DomainSignature]
public string PersonNummer { get; set; }

public string Namn {get; set; }
}

[Test]
public void SamePersonShouldNotBeAddedToSet()
{
var personer = new HashSet<Person>();
var person1 = new Person { PersonNummer = "123456-1234",
Namn = "Person1" };
var person2 = new Person { PersonNummer = "123456-1234",
Namn = "Person2" };

personer.Add(person1);
personer.Add(person2);

Assert.AreEqual(person1, person2);
Assert.AreNotSame(person1, person2);
Assert.AreEqual(1, personer.Count);
Assert.AreEqual("Person1", personer.Single().Namn);
}




On 5 Nov, 10:59, Torbjörn Kalin <torbjorn.ka...@gmail.com> wrote:
> Det hÀr Àr nÄgot som jag tycker Àr lÀskigt bÄde med hur
> SharpArchitecture löst det och med hur ad-hoc-lösningen verkar se ut.
>
> I SharpArchitecture Àr Equals() baserat pÄ Id:t om det finns (vaken
> this eller other Àr transienta). Annars anvÀnds "objektsignaturen" som
> Àr den naturliga nyckeln (typ personnummer) [1].
>
> Ad-hoc-lösningen Àr vÀl annars att bara anvÀnda Id:t (eller?).
>
> Om man anvÀnder generated Id:s Àndras alltsÄ objektets equals() nÀr
> man skriver det till databasen. Detta kan skapa problem om man vill
> lÀgga objekten t ex i ett Set (parent->child).
>
> NÄgon som har nÄgra tankar kring detta?
>
> /Torbjörn
>
> [1] En diskussion kring varför SharpArchitecture valt att göra sÄ
> finns beskrivet hÀr:http://devlicio.us/blogs/billy_mccafferty/archive/2007/04/25/using-eq...
> > > - Visa citerad text -- Dölj citerad text -

Torbjörn Kalin

unread,
Nov 6, 2010, 5:37:22 AM11/6/10
to DDD Sverige
I ditt exempel, vad hade du tÀnkt dig för strategi för att persistera
personerna?

För att fÄ in en ny Person i ett persisterat domÀnobjekt folksamling
vore det sweet om man kunde göra sÄ hÀr:

folksamling.add(new Person("123456-1234"));
folksamling.add(new Person("123456-1234"));

Vid commit gör Hibernate en dirty check och mÀrker att det finns _en_
ny Person att spara ner.

Detta sÀtt funkar bra i ditt fall eftersom du har ett naturligt domÀn-
Id och anvÀnder det i equals(). Det Àr lÄngt ifrÄn alltid man har det.
Hur gör man dÄ?

Ofta ser man dÀrför kod som ser ut sÄ hÀr (eller snarlikt):

Person p = new Person(...); // utan personnummer
p.makePartOf(folksamling);
personRepository.save(p);

Mycket kladdigare. Vad Àr personRepository för nÄgot?, undrar min
domÀnexpert.

/T

Mikael Egnér

unread,
Nov 6, 2010, 6:00:51 AM11/6/10
to DDD Sverige
Jag Àr nog inte riktigt med pÄ varför det skulle göra skillnad i ditt
exempel pÄ om man har ett naturligt DomÀn-Id eller inte.
PersonRepositoriet blir svÄrt att slippa, du mÄste ju pÄ nÄgot sÀtt
"nÄ persistens" för dina nya transienta objekt.
Men i ditt första exempel hade det ju kunnat vara sÄ hÀr :

folksamlingRepository.Get(folksamlingId)
folksamling.add(new Person("123456-1234"));
folksamling.add(new Person("123456-1234"));

//En ny person sparas i DB

Eller kanske försvenska det Ànnu mera om din domÀnexpert har problem
med sjÀlva order "repository" och anvÀnda just "samling" istÀllet

personSamling.Get(personSamlingId)
personSamling.add(new Person("123456-1234"));
personSamling.add(new Person("123456-1234"));

Men jag förstÄr inte riktigt varför du menar att inte nedanstÄende
skulle vara OK:
Person p = new Person(...); // utan personnummer
folksamling.add(p);

Dock sÄ mÄste du ju nÄgonstans sÀtta personnummer innan du sparar
eller validerar om du har det som ett krav

/Mikael

Niclas Nilsson

unread,
Nov 6, 2010, 6:38:17 AM11/6/10
to dddsv...@googlegroups.com
On 6 nov 2010, at 10.37, Torbjörn Kalin wrote:

> Ofta ser man dÀrför kod som ser ut sÄ hÀr (eller snarlikt):
>
> Person p = new Person(...); // utan personnummer
> p.makePartOf(folksamling);
> personRepository.save(p);
>
> Mycket kladdigare. Vad Àr personRepository för nÄgot?, undrar min
> domÀnexpert.

Fast det dÀr Àr kod som finns dÀr av tekniska skÀl och inte nÄgot som domÀnexperten skall behöva se? Anledningen att du ofta ser sÄdan kod Àr att folk av nÄgon anledning verkar ha lite svÄrt att skilja pÄ vad och hur (som inte skall vara pÄ samma stÀlle). Jag tror det beror pÄ att nÀr vi skriver koden tÀnker vi alltför lÀtt pÄ hur man gör en sak, och bryter ned det steg för steg just pÄ den platsen vi rÄkar komma pÄ "att" vi vill göra nÄgot.

Vad vill jag göra? LÀgga till personen i folksamlingen.

Hur gör jag det? Skapa ny instans, makePartOf o.s.v.

Av mÄnga skÀl Àr det en god idé att hur-koden ligger i en annan metod Àn dÀr vad-koden (d.v.s. intentionen, den som domÀnexperten dessutom Àr intresserad av) Àr. "Vad" blir bra metodanrop och "hur" passar ofta som smÄ, fina, fokuserade metoder.

Om domÀnexperten behöver se repot sÄ hade jag gÀrna döpt det till "persons" helt enkelt. Eller kanske Àven om de inte behöver se det.

Mvh
Niclas

---
http://niclasnilsson.se
http://twitter.com/niclasnilsson


Torbjörn Kalin

unread,
Nov 6, 2010, 12:08:14 PM11/6/10
to DDD Sverige
Det hÀr med personer och folksamling var en knepig, pÄhittad domÀn.
Jag ska försöka hitta ett bÀttre exempel dÀr det blir tydligare vad
som Àr aggregatrot och dÀr det inte existerar nÄgot domÀn-Id.

Samtidigt har jag just nu svÄrt att minnas det exakta scenariot som
ger det problem jag vill belysa. Just nu ser jag bara problem nÀr man
i samma use case vill lÀgga till flera children, nÄgot som inte kÀnns
sÄ vanligt.

Jag Äterkommer nÀr jag funderat pÄ det ett tag :)

/T

Jonas Andersson

unread,
Nov 7, 2010, 4:10:37 PM11/7/10
to dddsv...@googlegroups.com

DÄ tycker jag det Àr snyggare att det skapade objektet fÄr sitt unika ID direkt av Factyoryn. (Som jag löst det hitills - men nu funderar pÄ att byta till UUID - i mina "RepositoryInDB" sÄ automatgenereras ID frÄn en separat tabell med en automatrÀknad rad per EntityID som innehÄller senaste ID.

Det slog mig att i IDM/SSO-sfÀren sÄ anvÀnder man ocksÄ uttrycken entity och identity, och dÀr finns identifiers som ocksÄ unikt identifierar en entity, motsvarande verksamhetsattribut som personnummer alltsÄ. Egentligen Àr ju Entity-ID en förenkling av verkligheten vilket jag tenderar att glömma bort, ett pattern som ska underlÀtta för oss att modellera och implementera en lösning.
Det hjÀlpte mig iaf att acceptera lösningen med ett separat UUID

Ett försök till sammanfattning av fördelar med UUID som Entity-ID:

- Objektet har unikt ID frÄn födelsen.
- Att byta domÀn-id (som personnummer) blir enkelt, för att inte sÀga möjligt :)
- Equals Àr alltid deterministisk
- Alla "RepositoryVarianter" som Rep..InMem, Rep..InDB anvÀnder samma algoritm för ID-skapande (i motsats till min nuvarande lösning)


Skulle vara kul med nĂ„n DDD-bof e.d. pĂ„ Öredev förresten :)

-- Jonas


2010/11/5 Rickard Öberg <rickar...@gmail.com>
On 2010-11-05 06.21, Mikael Egnér wrote:
I Sharp Architecture (ramverk för .Net) sÀtter man ett attribut
"Domain Signature" pÄ de properties som unikt identifierar ett objekt

verksamhetsmÀssigt.

Alla egna entititesklasser Àrver frÄn basklassen Entity som har
överlagrar funktionerna Equals och GetHashCode (dessa funktioner Àr
viktiga för NHibernate (som Àr OR-ramverket som som Sharp

Architecture anvÀnder) Equals och GetHashCode baseras pÄ de
properties som Àr markerade med "Domain Signature" attributet

Entity-klassen innehÄller ocksÄ propertyn Id som Àr en integer och Àr
objektets tekniska id. (Om man behöver jobba med annat Àn integer som

teknisk nyckel finns en annan klass att Àrva ifrÄn)

Exempel pÄ anvÀndning PÄ klassen Person sÀtter man
DomainSignature-attributet pÄ personnummer propertyn

Detta gör att du kan skriva personA.Equals(personB) och fÄ svaret

true om instanserna har samma personnummer.

Detta verkar göra antagandet att tvÄ entiteter som Àr domÀn-mÀssigt identiska har olika tekniska id'n. Korrekt? Hur kan det komma sig att det finns tvÄ entiteter som representerar samma domÀnobjekt? Varför inte bara jÀmföra pÄ id't?

/Rickard


Reply all
Reply to author
Forward
0 new messages