[Alg/DDD] Repositories & domain classes

Pagina: 1
Acties:
  • 101 views sinds 30-01-2008
  • Reageer

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Een repository laadt een saved domein objecten in een persistence store. (db, xml file, whatever).

Nu zou je de repositories en de domein objecten in één assembly kunnen stoppen. Dit heeft als voordeel dat je domein object bv een methode heeft die enkel zichtbaar is binnen diezelfde assembly (dll). Die method gaat het domein object bv initialiseren met waardes uit de DB; je kan nog zo'n aantal methods hebben die bv een domein object als 'new' markeren, of als 'clean'/dirty, etc...
Er kleeft aan deze manier echter ook een nadeel:
de 'persistence logica' (nhibernate toestanden, zelf geschreven dal's, etc...) zullen ook in diezelfde assembly terechtkomen. (Dit kan niet gescheiden worden, aangezien je anders een circulaire referentie hebt).
Nu kan je natuurlijk de repositories in een andere assembly gaan stoppen en de domein objecten ook in een aparte assembly, maar hoe ga je dan gaan aangeven aan een object dat het 'new', 'dirty', 'clean' oid is ? Ik kan dat natuurlijk mbhv reflection gaan doen, maar dat heeft als nadeel dat je geen compile time checking hebt

De vraag : hoe pakken jullie het aan ?

[ Voor 6% gewijzigd door whoami op 04-11-2005 16:02 ]

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 03-02 12:37

pjvandesande

GC.Collect(head);

Waarom zou je het graag willen scheiden? Je Repository heeft toch altijd een referentie nodig naar je Domain Objects en misschien sommige Gateway's ook binnen je DAL.

Je kunt heel mooi dingen hidden maken door ze als internal te markeren. Er zijn toch altijd een hoop method's die je gewoon hidden wil hebben, zoals jij al aangeeft method die een Domain Object als New markeren of method's die een Domain Object initialiseerd adhv een DataRow oid.

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Waarom ik het graag wil scheiden: stel dat ik zowel een 'persistance layer' heb naar sql server, en naar oracle. Klanten die gebruik maken van sql server hoeven die oracle layer helemaal niet te hebben.
Als dit allemaal in één assembly zit, dan vind ik het trouwens ook onoverzichtelijk.

Maar misschien denk ik gewoon te veel na, en maak ik me teveel zorgen. 8)7

https://fgheysels.github.io/


Verwijderd

whoami schreef op vrijdag 04 november 2005 @ 15:56:
Een repository laadt een saved domein objecten in een persistence store. (db, xml file, whatever).

Nu zou je de repositories en de domein objecten in één assembly kunnen stoppen. Dit heeft als voordeel dat je domein object bv een methode heeft die enkel zichtbaar is binnen diezelfde assembly (dll). Die method gaat het domein object bv initialiseren met waardes uit de DB; je kan nog zo'n aantal methods hebben die bv een domein object als 'new' markeren, of als 'clean'/dirty, etc...
Er kleeft aan deze manier echter ook een nadeel:
de 'persistence logica' (nhibernate toestanden, zelf geschreven dal's, etc...) zullen ook in diezelfde assembly terechtkomen. (Dit kan niet gescheiden worden, aangezien je anders een circulaire referentie hebt).
Nu kan je natuurlijk de repositories in een andere assembly gaan stoppen en de domein objecten ook in een aparte assembly, maar hoe ga je dan gaan aangeven aan een object dat het 'new', 'dirty', 'clean' oid is ? Ik kan dat natuurlijk mbhv reflection gaan doen, maar dat heeft als nadeel dat je geen compile time checking hebt

De vraag : hoe pakken jullie het aan ?
weet niet of het werkt maar je kan een interface plaatsen in je repositorie assembly plaatsen. Alle domein objecten in je domein assembly erven van deze interface. In die interface plaats je die methods (IsNew, IsDirty etc etc).

op zon manier moet het denk ik. Maar om eerlijk te zijn heb ik geen ervaring met repositories (als je over die pattern bedoeld).

  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 03-02 12:37

pjvandesande

GC.Collect(head);

whoami schreef op vrijdag 04 november 2005 @ 16:28:
Waarom ik het graag wil scheiden: stel dat ik zowel een 'persistance layer' heb naar sql server, en naar oracle. Klanten die gebruik maken van sql server hoeven die oracle layer helemaal niet te hebben.
Als dit allemaal in één assembly zit, dan vind ik het trouwens ook onoverzichtelijk.
Dat is misschien wel waar. Maar dan zij het alleen je Gateway implementaties die in een apparte assembly kunnen. Ik zou de Repository's niet scheiden.

Maar correct me when i'm wrong!
Verwijderd schreef op vrijdag 04 november 2005 @ 16:32:
[...]

weet niet of het werkt maar je kan een interface plaatsen in je repositorie assembly plaatsen. Alle domein objecten in je domein assembly erven van deze interface. In die interface plaats je die methods (IsNew, IsDirty etc etc).

op zon manier moet het denk ik. Maar om eerlijk te zijn heb ik geen ervaring met repositories (als je over die pattern bedoeld).
Dan maak je het nog steeds niet hidden.
whoami schreef op vrijdag 04 november 2005 @ 16:28:Maar misschien denk ik gewoon te veel na, en maak ik me teveel zorgen. 8)7
Dat gevoel heb ik ook vaak :)

[ Voor 32% gewijzigd door pjvandesande op 04-11-2005 16:34 . Reden: Quote van B toegevoegd ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Verwijderd schreef op vrijdag 04 november 2005 @ 16:32:
[...]


weet niet of het werkt maar je kan een interface plaatsen in je repositorie assembly plaatsen. Alle domein objecten in je domein assembly erven van deze interface. In die interface plaats je die methods (IsNew, IsDirty etc etc).
Ja, dat doe ik ongeveer.
Zei het dan dat ik een aantal public getters heb, en een aantal internal setters.
Doordat die repositories en de domein objecten in dezelfde assembly zitten, kunnen die repositories dus de IsNew, en IsOld gaan setten.
Echter, als m'n repository er zo uit ziet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class PersonRepository
{

     private PersistanceStrategy _strat;

     public PersonRepository()
     {
          _strat = GetPersistanceStrategy(); // adhv een setting uit de config file wordt bv een
                                                             // oralce of sqlserver implementatie opgehaald.
     }

     public void Save( Person p )
     {
          if( p.IsNew)
          {
               int key = _strat.InsertNewPerson(p);
               p.Id = key;
               p.MarkOld();
          }
          else if( p.IsDirty )
          {
               _strat.UpdatePerson(p);
               p.MarkClean();
          }
     }
}


Nu, als ik dit heb, wil dit zeggen dat ik al m'n persistance-strategieën ook in dezelfde assembly moet hebben als m'n domain objecten (person) en m'n repository.
Ik kan m'n persistance strategieën (of de interface ervan) nl niet in een andere assembly stoppen, want deze assemblies hebben dan ook m'n domain objecten nodig. De assembly waar m'n repositories inzitten (en ook m'n domain objecten), hebben de assembly nodig waar m'n persistance strategie interface zit, want, zoals je ziet, nemen die een domain object als parameter.
-> circulaire referentie dus.

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Ik kan natuurlijk van 'transfer objecten' gebruik gaan maken;

Dan heb ik dit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class PersonRepository
{
      ...
      public void Save( Person p )
      {
           PersonTransfer pt = new PersonTransfer();
           pt.Name = p.Name;
           ....
           if( p.IsNew )
           {
                _strat.InsertPerson(pt);
                ...
           }
           ...
      }
}

Maar, dan zit ik natuurlijk weer met een aantal extra classes, die ook weer moeten aangepast worden als er iets in m'n db veranderd, etc...

https://fgheysels.github.io/


Verwijderd

whoami schreef op vrijdag 04 november 2005 @ 16:39:
[...]

Ja, dat doe ik ongeveer.
Zei het dan dat ik een aantal public getters heb, en een aantal internal setters.
Doordat die repositories en de domein objecten in dezelfde assembly zitten, kunnen die repositories dus de IsNew, en IsOld gaan setten.
Echter, als m'n repository er zo uit ziet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class PersonRepository
{

     private PersistanceStrategy _strat;

     public PersonRepository()
     {
          _strat = GetPersistanceStrategy(); // adhv een setting uit de config file wordt bv een
                                                             // oralce of sqlserver implementatie opgehaald.
     }

     public void Save( Person p )
     {
          if( p.IsNew)
          {
               int key = _strat.InsertNewPerson(p);
               p.Id = key;
               p.MarkOld();
          }
          else if( p.IsDirty )
          {
               _strat.UpdatePerson(p);
               p.MarkClean();
          }
     }
}


Nu, als ik dit heb, wil dit zeggen dat ik al m'n persistance-strategieën ook in dezelfde assembly moet hebben als m'n domain objecten (person) en m'n repository.
Ik kan m'n persistance strategieën (of de interface ervan) nl niet in een andere assembly stoppen, want deze assemblies hebben dan ook m'n domain objecten nodig. De assembly waar m'n repositories inzitten (en ook m'n domain objecten), hebben de assembly nodig waar m'n persistance strategie interface zit, want, zoals je ziet, nemen die een domain object als parameter.
-> circulaire referentie dus.
wat je kan doen is een normale classe plaatsen in je repository. Zorg ervoor dat deze classe erft van de interface. Alle domein klasse in je domein assembly erven vervolgens van deze classe.

Person kan je nu vervangen met die classe. Ik zal als ik jou was een super classe maken waarvan PersonRepository erft. Daar kan je al je generieke methods plaatsen als het saven, update en deleten etc etc. Maar misschien is het handiger om een classe diagram te laten zien. dat geeft een beter beeld.

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Nee, dat kan ik niet, want ik wil in m'n repository en vooral in m'n 'strategy' aan de verschillende specifieke properties van person kunnen.

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 03-02 12:37

pjvandesande

GC.Collect(head);

whoami schreef op vrijdag 04 november 2005 @ 16:48:
Ik kan natuurlijk van 'transfer objecten' gebruik gaan maken;
Dit geeft alleen maar extra werk denk ik en maakt de boel complexer. Je kunt best alles in 1 assembly houden, maar als je het echt wilt scheiden heb je een extra laag nodig.

Als je alles netjes indeeld in Namespaces dan hou je nog best wel wat overzicht. Ik denk dat het scheiden gewoon teveel nadelen heeft.

edit:
Hoe zou alleen je Transfer object er uit komen te zien?

[ Voor 9% gewijzigd door pjvandesande op 04-11-2005 17:15 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
* whoami gaat dit eens lezen

Tja, ik kan misschien met behulp van ioc de gewenste impl. gaan ophalen.

[ Voor 26% gewijzigd door whoami op 04-11-2005 18:08 ]

https://fgheysels.github.io/


  • Scare360
  • Registratie: Juli 2001
  • Laatst online: 15:40
whoami schreef op vrijdag 04 november 2005 @ 17:33:
* whoami gaat dit eens lezen

Tja, ik kan misschien met behulp van ioc de gewenste impl. gaan ophalen.
Dat is een post geschreven naar aanleiding van een huidig project. De huidige impelementatie gebruikt hier idd spring.net1.0 voor.

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Maar als ik het goed begrijp heb jij dan bv voor Customer meerdere repositories ?
Ik zit eerder te denken aan één repository voor iedere aggregate, en die repository heeft dan een 'IGateway' oid, en die repository roept dan die gateway aan.

Ben net eens naar Spring.NET a/h kijken.

https://fgheysels.github.io/


  • Scare360
  • Registratie: Juli 2001
  • Laatst online: 15:40
whoami schreef op vrijdag 04 november 2005 @ 21:09:
Maar als ik het goed begrijp heb jij dan bv voor Customer meerdere repositories ?
Weet niet hoe je daar bij komt? De CustomerRepository interface zit in de Domain package en de CustomerRepositoryImpl in de Repositories package. In de RepositoryStubs package zitten, zoals de naam al zegt, stubs welke via een plugin pattern geladen worden afhankelijk van configuratie.

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Nog een ander probleem wat misschien wat off-topic is. Waar ik vaak tegen aan loop is dat de persistance layer op een andere manier de domain classes moet kunnen benaderen dan de user interface layer.

Voorbeeld: een User class heeft een property EncryptedPassword. Deze moet voor de persistance layer writable zijn, maar de gebruikers interface heeft hier niks aan en moet alleen een SetPassword methode hebben.

Is het werkelijk zo slecht dat een business object zichzelf mag vullen met gegevens? Dus dat vanuit de persistance layer de gegevens niet in de business objecten worden geplaatst, maar dat de business objecten zichzelf vullen met gegevens uit de persistance layer?

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op vrijdag 04 november 2005 @ 16:28:
Waarom ik het graag wil scheiden: stel dat ik zowel een 'persistance layer' heb naar sql server, en naar oracle. Klanten die gebruik maken van sql server hoeven die oracle layer helemaal niet te hebben.
Als dit allemaal in één assembly zit, dan vind ik het trouwens ook onoverzichtelijk.
Maar misschien denk ik gewoon te veel na, en maak ik me teveel zorgen. 8)7
Je kunt ook gewoon iets gebruiken waarvan de makers al hebben nagedacht over dit ;)

Laat ik voorop stellen dat ik niet geloof in POCO/POJO. Ik heb nog nooit 1 argument gehoord wat dermate belangrijk was dat het alle tegenargumenten teniet doet (tegenargumenten: changetracking logic, databinding aware code, xml / remoting serialization aware code etc. )

Non-poco entities bevatten dus al een deel code dat je kunt toeschrijven aan 'de persistence layer'. Dit is niet erg, de persistence layer is immers onderdeel van je applicatie.

Echter, je kunt het scheiden: je hebt entity-focussed logic (changetracking/ xml/remoting serialization / field versioning code / graph maintenance code) IN de entity classes zitten maar geen persistence data noch logica. Die plaats je in een database specific onderdeel, 1 per database type. Je kunt nu de generieke entities (generiek in de zin van: database independent) aanbieden aan ieder database specifieke onderdeel, en die 'merged' de persistence data van het entity type met het entity en processt het geheel verder (query aanmaken, verwerken etc.)

Zo doe ik het ook, je hebt een database generic onderdeel (dat je kunt gebruiken met sqlserver/oracle of andere supported db) en je hebt een database specific onderdeel. Je moet wel per db dezelfde mappings hebben, maar in jouw geval kun je dat wellicht nog tunen ook. (ik heb bv database specific type converters, dus dat je in oracle een .NET boolean mapt op NUMBER(1,0) maar in sqlserver converteert hij niets en mapt hij hem op een bit field. )

Voordeel is dat je je applicatie volledig database onafhankelijk kunt opbouwen en houden. Het enige wat je moet doen is een database specific onderdeel erbij plaatsen voor een nieuwe database die je support en dat is alles.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
EfBe schreef op zaterdag 05 november 2005 @ 13:19:
[...]

Laat ik voorop stellen dat ik niet geloof in POCO/POJO. Ik heb nog nooit 1 argument gehoord wat dermate belangrijk was dat het alle tegenargumenten teniet doet (tegenargumenten: changetracking logic, databinding aware code, xml / remoting serialization aware code etc. )
Daar ben ik het mee eens. Als je domain objecten weten of ze nieuw, gewijzigd, etc... zijn, en als ze databinding ondersteunen, dan is het zo veel makkelijker.
Echter, jij zegt ook dat ze geen logica mogen bevatten; dat is natuurlijk een ander 'point of view', maar ik vind het logischer als ze wel logica bevatten.
Als ik refereer naar dit artikel op jouw weblog, dan zie ik mezelf eerder in kamp 3.

Hoe denk jij trouwens over het bijhouden van 'state' binnen een object/entiteit ?
[rml][ DDD] Verwijderen van objecten uit collecties en undo-ing[/rml]

Het CSLA.NET framework van Rokford Lhotka heeft zoiets, maar wat ik dan weer niet goed vind aan dat framework is het feit dat z'n DB access in z'n domein classes zit, en daarbij ook de transactie-handling. Iets wat zowiezo niet in een business class thuishoort.

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
paulgielens schreef op vrijdag 04 november 2005 @ 21:03:
[...]


Dat is een post geschreven naar aanleiding van een huidig project. De huidige impelementatie gebruikt hier idd spring.net1.0 voor.
Maar heb je dan ook in je assembly waar de repository interface & de domain objects zich bevinden geen referentie naar die assembly waar de repository implementatie zich bevindt ?
Mijn idee zou zijn van niet, want dat is ook één van de bedoelingen van jouw opzet, maar ik ben er nog niet in geslaagd om mbhv spring.net een instance te maken van een object dat zich in een assembly bevindt waar ik geen reference naar heb.

Als ik de assembly in m'n application directory zet, dan lukt het wel. :P

[ Voor 6% gewijzigd door whoami op 05-11-2005 16:50 ]

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op zaterdag 05 november 2005 @ 15:30:
Daar ben ik het mee eens. Als je domain objecten weten of ze nieuw, gewijzigd, etc... zijn, en als ze databinding ondersteunen, dan is het zo veel makkelijker.
Echter, jij zegt ook dat ze geen logica mogen bevatten; dat is natuurlijk een ander 'point of view', maar ik vind het logischer als ze wel logica bevatten.
Je hebt IMHO 3 soorten BL logica:
1) field focussed BL (id >0)
2) entity focussed BL (shipdate >= orderdate)
3) cross entity focussed BL (customer is gold customer if has ordered > 50orders in past n months)

1 en 2 kunnen in een entity, 3 IMHO niet.
Hoe denk jij trouwens over het bijhouden van 'state' binnen een object/entiteit ?
[rml][ DDD] Verwijderen van objecten uit collecties en undo-ing[/rml]

Het CSLA.NET framework van Rokford Lhotka heeft zoiets, maar wat ik dan weer niet goed vind aan dat framework is het feit dat z'n DB access in z'n domein classes zit, en daarbij ook de transactie-handling. Iets wat zowiezo niet in een business class thuishoort.
State moet je imho altijd in een entity bijhouden, het hoort immers bij de data, wat eigenlijk de entity is. Het object is een container voor de entity. Versioning is een complex probleem overigens. Ik heb wel een field versioning (dus echte atomic unitofwork commits en waarbij je dus zelf fields kunt versionen in een entity object) maar graph versioning is wel wat lastiger: je hebt customer, met 2 address objects, een paar order objects etc. en die push je naar een scherm. User edit de handel en besluit toch op cancel te klikken. Wat nu? Dat is echt niet 1 2 3 te doen. (graph snapshots lossen dit op, maar is erg lastig te realiseren in een redelijke tijd)

Ik ben wel voorstander van dat wanneer je bv een order entity uit myCustomer.Orders verwijdert met Remove, de CustomerID van dat order object op null wordt gezet, en ook wanneer je myOrder.CustomerID op een andere waarde zet, dat myOrder dan uit de Orders collection van de Customer entity wordt verwijderd waarde deze in zat, en dat ondersteun ik ook. Ik weet niet of je dat bedoelde met je opmerking ;)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
EfBe schreef op zaterdag 05 november 2005 @ 17:40:
[...]

Je hebt IMHO 3 soorten BL logica:
1) field focussed BL (id >0)
2) entity focussed BL (shipdate >= orderdate)
3) cross entity focussed BL (customer is gold customer if has ordered > 50orders in past n months)

1 en 2 kunnen in een entity, 3 IMHO niet.
Ik ben het met je eens dat niet alle BL in je entity kan; echter, het voorbeeld dat je aanhaalt is misschien niet zo'n goed voorbeeld.
Als je 'Customer' entity een collectie heeft van Orders, dan kan je die 'IsGoldCustomer' logica daar wel in kwijt.
De vraag is natuurlijk wel of je dat wilt. Een DB zou het antwoord op die vraag veel sneller kunnen leveren dunkt me.
State moet je imho altijd in een entity bijhouden, het hoort immers bij de data, wat eigenlijk de entity is. Het object is een container voor de entity. Versioning is een complex probleem overigens. Ik heb wel een field versioning (dus echte atomic unitofwork commits en waarbij je dus zelf fields kunt versionen in een entity object) maar graph versioning is wel wat lastiger: je hebt customer, met 2 address objects, een paar order objects etc. en die push je naar een scherm. User edit de handel en besluit toch op cancel te klikken. Wat nu? Dat is echt niet 1 2 3 te doen. (graph snapshots lossen dit op, maar is erg lastig te realiseren in een redelijke tijd)
Rocky Lothka heeft dit imho opgelost dmv reflection en serialization. Dit is best een mooie oplossing.
Z'n objecten hebben beginedit, cancel- en commitedit methods, die je toelaten om het object terug in z'n vorige state te zetten. of bedoel je dat niet ?
Ik ben wel voorstander van dat wanneer je bv een order entity uit myCustomer.Orders verwijdert met Remove, de CustomerID van dat order object op null wordt gezet, en ook wanneer je myOrder.CustomerID op een andere waarde zet, dat myOrder dan uit de Orders collection van de Customer entity wordt verwijderd waarde deze in zat, en dat ondersteun ik ook. Ik weet niet of je dat bedoelde met je opmerking ;)
Mmm, niet echt...
Het ging er eerder over dat, als je iets uit een collectie verwijderd (een order bv), dat je dat niet 'echt' wilt verwijderen, zolang de wijzigingen niet gepersisteerd worden naar de DB. (Bij het verwijderen uit de DB moet je nl. het id van het order weten, en als je besluit van 'op cancel' te drukken, wil je dat order terug hebben.

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op zaterdag 05 november 2005 @ 18:18:
Rocky Lothka heeft dit imho opgelost dmv reflection en serialization. Dit is best een mooie oplossing.
Z'n objecten hebben beginedit, cancel- en commitedit methods, die je toelaten om het object terug in z'n vorige state te zetten. of bedoel je dat niet ?
Ja, alleen dan per graph, niet per object. Je kunt het idd met serialization oplossen, maar je MOET per graph werken:
je hebt een Customer object en 2 Address objects. Je wijzigt VisitingAddressID in Customer, en de customer verdwijnt als Address.VisitingAddressForCustomer want die wordt dan null. Dus niet alleen Customer wijzigt, ook de gerelateerde objects.
[...]
Mmm, niet echt...
Het ging er eerder over dat, als je iets uit een collectie verwijderd (een order bv), dat je dat niet 'echt' wilt verwijderen, zolang de wijzigingen niet gepersisteerd worden naar de DB. (Bij het verwijderen uit de DB moet je nl. het id van het order weten, en als je besluit van 'op cancel' te drukken, wil je dat order terug hebben.
Ohh! Inderdaad, removes uit een collection kan IMHO niet gelijk staan aan verwijderen uit de database. Immers, een collection in memory is ook t.a.t. een snapshot en behoeft niet de gehele collection te zijn (je laadt een customer in en alleen zn 10 laatste orders, daar dan een order uit verwijderen zegt IMHO dan alleen dat je een order uit de results haalt, maar niet dat je die order niet meer gerelateerd wilt zien aan die customer.

Veel mensen willen dat overigens wel, hoevaak ik die vraag niet krijg... Wat ik wel raar vind, want het is per saldo een ambigue actie.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Scare360
  • Registratie: Juli 2001
  • Laatst online: 15:40
whoami schreef op zaterdag 05 november 2005 @ 18:18:

Rocky Lothka heeft dit imho opgelost dmv reflection en serialization. Dit is best een mooie oplossing.
Z'n objecten hebben beginedit, cancel- en commitedit methods, die je toelaten om het object terug in z'n vorige state te zetten. of bedoel je dat niet ?
Gruwelijk! Dit doet hij om het mogelijk te maken objecten aan winform/web controls te binden. Als je er echt werk van maakt om tot een rijk domein model te komen moet je deze weg niet inslaan. Zie http://weblogs.asp.net/pg...ve/2005/10/14/427493.aspx voor UI mappers.

Veel developers lezen het Evans boek, beginnen aan DDD en beseffen niet wat daarvan de consequenties zijn. Als je denkt DDD te doen, waar je vervolgens energie steekt in presentatie en workflow binnen zo'n zelfde package... klopt er iets niet.

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Ik heb het DDD boek van Evans hier ook liggen.
Die 'undoable' functionaliteit van Lothka vind ik niet zo gruwelijk; het is een generieke oplossing voor iets wat je zowiezo nodig hebt.
Het kan je klant toch niets schelen of je nu een puur domein model hebt, of als je domein classes 'vervuild' zijn met deze logica of databinding logica. Zolang z'n applicatie maar doet wat hij moet doen.
Is het zo erg om je domein classes te laten inheriten van een base class die deze functionaliteit aanbiedt ? Nee toch...

Ik heb een tijdje gelezen eens een blogpost gelezen over UI mappers, en eigenlijk is het niet meer dan weer een extra laag, weer extra complexiteit, etc....

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
paulgielens schreef op zondag 06 november 2005 @ 10:36:
[...]
Gruwelijk! Dit doet hij om het mogelijk te maken objecten aan winform/web controls te binden. Als je er echt werk van maakt om tot een rijk domein model te komen moet je deze weg niet inslaan. Zie http://weblogs.asp.net/pg...ve/2005/10/14/427493.aspx voor UI mappers.
UI mappers zijn wel leuk, het is eigenlijk gewoon het MVC verhaal, alleen dan met een pre-defined controller, maar vergeet niet dat het niet allemaal vanzelf gaat.
Veel developers lezen het Evans boek, beginnen aan DDD en beseffen niet wat daarvan de consequenties zijn. Als je denkt DDD te doen, waar je vervolgens energie steekt in presentatie en workflow binnen zo'n zelfde package... klopt er iets niet.
valt wel mee. Het probleem is dat veel van de DDD ideeen vanuit de javawereld zijn overgewaaid. Daar kent men niet het fenomeen databinding zoals we dat in de MS wereld kennen, en zeker niet de implementatieeisen die de MS databinding aan je objects stelt.

Wil je rijke databinding dat zit je al snel aan UI gerelateerde code. Voorbeeld: je wilt Customer.Orders binden aan een grid. Als die collectie leeg is wil je WEL een setje columns zien.

Nu kun je ITypedList implementeren in je Orders collection (en IBindingList zodat de grid niet over de zeik gaat) en je weet zelf wat voor feest dat is :). Maar zodra je dat doet, heb je wel UI code in je entity collection.

Je kunt ook IListSource implementeren en met die interface een UI bindable object opleveren, een 'view' op je collection zeg maar. Dit lijkt beter, maar ook daar heb je het nadeel dat IListSource voor niets anders dient dan databinding en dus UI gerelateerde zaken.

Je kunt het oplossen door een abstracte layer te bouwen die dmv reflection de viewer genereert at runtime, maar dat vereist weer non-standaard code, nl. dat je niet iets doet als:
myGrid.DataSource = myCustomers.Orders;

maar dat je die abstracte layer vertelt dat je tussen control A en collection C een binding wilt opzetten. Nu zal dat binnen 1 project nog wel gaan maar het grote nadeel is dat het totaal niet design time werkt. Geloof me, de meeste mensen willen muizen ipv tikken in dit kader.

Dus... hoe los JIJ dit dan op? :) IMHO is er nl. niet zoveel ruimte voor iets wat algemeen werkt en je objects gewoon met rust laat.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Scare360
  • Registratie: Juli 2001
  • Laatst online: 15:40
EfBe schreef op zondag 06 november 2005 @ 15:44:Dus... hoe los JIJ dit dan op? :) IMHO is er nl. niet zoveel ruimte voor iets wat algemeen werkt en je objects gewoon met rust laat.
In mijn huidig project hebben we een Presentation package die domein objecten naar views vertaalt en de implementatie daarvan is inderdaad vergelijkbaar met een MVC. De databinding in .NET 2.0... daar kan ik me iets bij voorstellen, maar die in 1.0 is dermate slecht dat dit een eigen binding implementatie rechtvaardigd.
EfBe schreef op zondag 06 november 2005 @ 15:44:
Het probleem is dat veel van de DDD ideeen vanuit de javawereld zijn overgewaaid.
Klopt! Ik ben dan ook heel benieuwd hoe MS DDD denkt aan te vliegen, want zodra ze DSL's introduceren kunnen ze er niet meer omheen.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

EfBe schreef op zondag 06 november 2005 @ 15:44:
[...]
Wil je rijke databinding dat zit je al snel aan UI gerelateerde code. Voorbeeld: je wilt Customer.Orders binden aan een grid. Als die collectie leeg is wil je WEL een setje columns zien.
Dit lijkt me iets dat ook wel tijdens een vertaalproces ingesteld kan worden mbv een bepaalde regel. Ik zie geen reden waarom dit onderdeel van je domain model zou moeten zijn. Eventueel zou dit nog via een stuk metadata (.net attributes in je code.. gedsie.. of in een apart xml bestand.. minder getsie) nog op te lossen zijn.

[ Voor 25% gewijzigd door Alarmnummer op 06-11-2005 21:26 ]


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Alarmnummer schreef op zondag 06 november 2005 @ 21:21:
[...]
Dit lijkt me iets dat ook wel tijdens een vertaalproces ingesteld kan worden mbv een bepaalde regel. Ik zie geen reden waarom dit onderdeel van je domain model zou moeten zijn. Eventueel zou dit nog via een stuk metadata (.net attributes in je code.. gedsie.. of in een apart xml bestand.. minder getsie) nog op te lossen zijn.
Alleen als je een surrogate object bind. Als je direct customer.Orders bind en Orders is een collection dan kun je het vergeten als je niet ITypedList implementereert, je krijgt dan geen columns bij een lege collection. Dus je moet zelf actief een wrapper instantiaten, waarbij je je collection als eigenlijke bron meegeeft en waarbij die wrapper dan wordt gebind, en die wrapper gaat dan de columns genereren (hoe, dat is een ander verhaal en het klinkt wellicht makkelijk maar implementeer ITypedList maar eens ;))

De ellende begint wanneer de user de hierarchie inbrowst :) Veel plezier :)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:26
Een bijkomende vraag is of je je Orders collectie wel zomaar beschikbaar wilt stellen vanuit je Customer object.
Dat zou nl. willen zeggen dat je dan:
code:
1
Customer1.Orders.Add (order);

kunt aanroepen, terwijl je misschien wel een AddOrder( Order o ) method hebt in je Customer class die een aantal extra zaken gaat uitvoeren (zoals bv. de Customer property van het Order gaan zetten)
code:
1
2
3
4
5
public void AddOrder ( Order o )
{
    o.Customer = this;
    _orders.Add(o);
}

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op maandag 07 november 2005 @ 11:12:
Een bijkomende vraag is of je je Orders collectie wel zomaar beschikbaar wilt stellen vanuit je Customer object.
Dat zou nl. willen zeggen dat je dan:
code:
1
Customer1.Orders.Add (order);

kunt aanroepen, terwijl je misschien wel een AddOrder( Order o ) method hebt in je Customer class die een aantal extra zaken gaat uitvoeren (zoals bv. de Customer property van het Order gaan zetten)
code:
1
2
3
4
5
public void AddOrder ( Order o )
{
    o.Customer = this;
    _orders.Add(o);
}
Customer1.Orders.Add(order); zet toch de Customer property van order? Althans dat zou ik verwachten. EN wanneer Customer1 niet nieuw is ook order.CustomerID = Customer1.CustomerID

Maar als je inderdaad kiest voor AddOrder() zul je een readonly collection moeten returnen via Orders. Het punt is alleen dat je dan grote moeilijkheden krijgt wanneer je in een grid een nieuwe row wilt toevoegen. Ik hou ook niet van grids als editors maar sommige mensen lussen er wel pap van, en dan gaat jouw oplossing niet werken.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com

Pagina: 1