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

36 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