[Alg] Domain Driven Design / Transaction Handling

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

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Ik zit met een ei. :)

Stel dat je een applicatie hebt, die op een n-tier manier gebouwd wordt.

Ik heb in die applicatie bv een data-access laag en een 'provider'-laag.

M'n client praat met m'n provider, en m'n provider returned business objecten en is verantwoordelijk om business objecten te saven.
bv:
code:
1
2
3
4
5
Customer c = customerProver.GetCustomer (id);

// do some stuff

customerProvider.Save (c);


De GetCustomer haalt in dit geval de klant op met zijn orders bv. (Customer is in dit geval dus een 'aggregate root' (om in het Evans woorden te zeggen), die een collectie heeft van Order objecten).
De Save method gaat in dit geval de wijzigingen aan de customer saven, en ook de wijzigingen aan de Order objecten.

Allemaal goed en wel, in dit geval zou je kunnen zeggen dat de Transactie-handling (start-transaction call, commit en rollback call) in de CustomerProvider thuis horen.

Echter, in bepaalde situaties is dit niet voldoende. Soms kan het zijn dat ik mijn transactie over meer dan één 'aggregate root' wil laten lopen.
Daarom zou het dus eigenlijk het beste zijn dat ik mijn 'client' verantwoordelijk laat zijn voor het starten / committen / rollbacken van transacties.
Echter, dan is nu mijn vraag hoe ik dat het best doorgeef aan m'n providers...

Ik kan dat natuurlijk wel zo doen:
code:
1
2
3
4
5
6
transactionSession = App.BeginTransaction();

customerProvider.Save (transactionSession, customer);
customerProvider.Save (transactionSession, customer2);

transactionSession.Commit();


Echter, dan 'vervuil' ik m'n client wel met dat transactie-gedoe, maar ik zie niet in hoe het anders kan.
Ik heb dan ook wel een extra parameter in m'n Save method die het boeltje er imho ook niet echt duidelijker op maakt.

Iemand die hier een goed idee over heeft ?

https://fgheysels.github.io/


  • Orphix
  • Registratie: Februari 2000
  • Niet online
Er even van uitgaande dat je een enkele transactie per thread per keer wilt hebben zou je een class kunnen maken die de transacties regelt. Deze class zorgt ervoor dat er bij de eerste aanroep van BeginTransaction() daadwerkelijk een transactie wordt aangemaakt (static) en die wordt gereturned. Bij alle BeginTransaction() aanroepen daarna (dus van de provider) wordt de reeds bestaande transactie geretourneerd, en een teller verhoogd met 1.
Bij een commit() wordt de teller verlaagd met 1. Als de teller 0 is wordt de transactie daadwerkelijk gecommit.

Nadeel is wel dat de semantische betekenis van commit() niet meer correct is. Immers na je commit() kan je er niet zeker van zijn dat de data ook daadwerkelijk gecommit is omdat er nog een bovenliggende laag kan zijn die een transactie heeft draaien.

Ik vind het trouwens helemaal niet zo'n vieze oplossing eigenlijk. Misschien voelt dat zo aan omdat het in de presentatie laag plaatsvindt ? Dan zou je kunnen overwegen om het naar de businness rules laag te verplaatsen.

[ Voor 13% gewijzigd door Orphix op 22-05-2005 02:20 ]


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

Alarmnummer

-= Tja =-

Je zou op je service layer een methode saveAll kunnen maken die alles onder een transactie commit.
De vraag is (ivm veiligheid) of je wilt dat iedereen maar alles kan saven en of je niet een business methode: geeftIedereenDikkeRooieNeusEnPruik(List managers) had kunnen hebben. Vaak kan je door een savemethode echt alles naar de db saven en kan het 1) een security drama worden 2) een logica drama, aangezien je geen extra acties kunt ondernemen.

Nog een leuk probleem:
Veel or-mappers maken gebruik van lazy loading. Als jij van je service/provide (jij noemt dit provider laag.. aaarrggghh... nog een naam) een object terug krijgt, dan is je actie in principe afgerond: de transactie is gecommit. Als jij nu dit object in de view gaat renderen, en er zouden ongeladen stukken inzitten, dan zouden deze stukken ingeladen moeten worden onder dezelfde transactie als je hebt gebruikt onder bij je service laag, maar deze is al dicht -> je hebt dus een probleem aangezien je waarschijnlijk een database exception "no open transaction found" voor de kiezen zult krijgen.

Ik erger me eerlijk gezegd een beetje aan alle dingen die over de service laag worden gezegd. Er zijn meer dan genoeg andere systemen waarbij een 1000-voud aan complexere problemen te vinden zijn, maar doordat iedereen maar uit zijn nek blijft lullen, en iedereen er andere namen aan geeft, is het erg onduidelijk geworden. Iedereen roept weer iets anders.. wel logica in objecten.. geen logica in objecten.. dao`s in domain objecten.. geen dao`s in domain objecten.. aparte service layer.. geen service layer.. etc etc. Ik heb mijn buik er eerlijk gezegd behoorlijk van vol. Wat is trouwens wel een redelijk handige techniek vind hier is een "ignore where sentence contains martin fowler"

[ Voor 36% gewijzigd door Alarmnummer op 22-05-2005 07:13 ]


  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 09-01 10:13

MaxxRide

Surf's up

Je zou op het service layer natuurlijk ook een aggregatie van "aggregate-root" objecten kunnen maken die hier verantwoordelijk voor is. Als ik je verhaal zo beoordeling wellicht wat tegen het principe in, maar ja er worden iedere dag dingen opnieuw bedacht en software engineering is nou eenmaal in ontwikkeling, dus sla je slag ;)

If you are not wiping out you are nog pushing enough...


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Orphix schreef op zondag 22 mei 2005 @ 02:18:
Ik vind het trouwens helemaal niet zo'n vieze oplossing eigenlijk. Misschien voelt dat zo aan omdat het in de presentatie laag plaatsvindt ? Dan zou je kunnen overwegen om het naar de businness rules laag te verplaatsen.
Ik kan het niet verplaatsen naar de BL laag, want eigenlijk is het pas in de client dat je kunt weten wat er binnen een bepaalde transactie hoort... -> dat is ook de reden waarom ik ze niet in die 'providers' kan steken.
Alarmnummer schreef op zondag 22 mei 2005 @ 07:08:
Je zou op je service layer een methode saveAll kunnen maken die alles onder een transactie commit.
De vraag is (ivm veiligheid) of je wilt dat iedereen maar alles kan saven en of je niet een business methode: geeftIedereenDikkeRooieNeusEnPruik(List managers) had kunnen hebben. Vaak kan je door een savemethode echt alles naar de db saven en kan het 1) een security drama worden 2) een logica drama, aangezien je geen extra acties kunt ondernemen.
Hmm, iets om over na te denken.
Nog een leuk probleem:
Veel or-mappers maken gebruik van lazy loading. Als jij van je service/provide (jij noemt dit provider laag.. aaarrggghh... nog een naam) een object terug krijgt, dan is je actie in principe afgerond: de transactie is gecommit. Als jij nu dit object in de view gaat renderen, en er zouden ongeladen stukken inzitten, dan zouden deze stukken ingeladen moeten worden onder dezelfde transactie als je hebt gebruikt onder bij je service laag, maar deze is al dicht -> je hebt dus een probleem aangezien je waarschijnlijk een database exception "no open transaction found" voor de kiezen zult krijgen
Nog iets om over na te denken. Bah, je hebt wel gelijk.
In principe zou ik dus in dit opzicht niet mogen werken met lazy loading, en alles direct inladen.
Echter, als je van lazy loading gebruik maakt, dan kan je toch ook de dingen die je 'lazy wilt inladen' ook niet binnen dezelfde transactie gaan inladen als je 'hoofd' object. Als je dat wel doet, dan blijft je transactie veel te lang open staan toch ?
Ik heb mijn buik er eerlijk gezegd behoorlijk van vol.
Ik eigenlijk ook.
Het probleem is echter dt er geen 'heilige graal' of 'beste oplossing' bestaat. Ieder probleem is anders, en er is geen oplossing die voor alle situaties past.
MaxxRide schreef op zondag 22 mei 2005 @ 09:11:
Je zou op het service layer natuurlijk ook een aggregatie van "aggregate-root" objecten kunnen maken die hier verantwoordelijk voor is. Als ik je verhaal zo beoordeling wellicht wat tegen het principe in, maar ja er worden iedere dag dingen opnieuw bedacht en software engineering is nou eenmaal in ontwikkeling, dus sla je slag ;)
Daar heb ik ook aan gedacht, maarja, wat als je nu binnen één transactie 2 of meer objecten wilt opslaan die eigenlijk van een ander type zijn ?

[ Voor 75% gewijzigd door whoami op 22-05-2005 10:22 ]

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 22 mei 2005 @ 10:15:
Nog iets om over na te denken. Bah, je hebt wel gelijk.
In principe zou ik dus in dit opzicht niet mogen werken met lazy loading, en alles direct inladen.
Echter, als je van lazy loading gebruik maakt, dan kan je toch ook de dingen die je 'lazy wilt inladen' ook niet binnen dezelfde transactie gaan inladen als je 'hoofd' object. Als je dat wel doet, dan blijft je transactie veel te lang open staan toch ?
Ik denk het niet. Als de transactie aan het einde van de webrequest afgesloten zou worden zou dat niet veel later zijn dan in de service layer. In principe zou de service layer alleen goedkeuring aan de commit (of afkeuring) mogen geven maar de daadwerkelijke commit niet mogen uitvoeren, zodat je bij het afsluiten van de transactie voor die webrequest kunt comitten of rollbacken. Dit probleem heet trouwens 'open session in view'
Het probleem is echter dt er geen 'heilige graal' of 'beste oplossing' bestaat. Ieder probleem is anders, en er is geen oplossing die voor alle situaties past.
Ben ik voor een gedeelte met je eens. Maar vaak worden verschillende namen voor dezelfde dingen gebruikt en soms worden dezelfde namen voor verschillende dingen gebruikt (bv een value object 1) ook bekend als dto.. 2) geen dto maar indicatie dat het een identiteitloos object is). In principe valt de schade nog te overzien als je in een bepaald kamp blijft. Ik zit veel in het Spring kamp dus ik snap precies wat ze ermee bedoelen. Ik denk dat dit een foute ontwikkeling is..

Als ik kijk naar andere aspecten van webapplicaties en applicaties in het algemeen is hier veel minder onduidelijkheid over.

[ Voor 11% gewijzigd door Alarmnummer op 22-05-2005 12:13 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Alarmnummer schreef op zondag 22 mei 2005 @ 12:11:
[...]

Ik denk het niet. Als de transactie aan het einde van de webrequest afgesloten zou worden zou dat niet veel later zijn dan in de service layer.
Ah, als je ervan uitgaat dat je met een web-applicatie werkt.... Ik werk eigenlijk voornamelijk met 'rich client' app's.

[ Voor 9% gewijzigd door whoami op 22-05-2005 12:14 ]

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 22 mei 2005 @ 12:13:
[...]
Ah, als je ervan uitgaat dat je met een web-applicatie werkt....
Dat zelfde zou opgaan als je niet met een webapp werkt. Als je informatie terug zou krijgen over de status van de transactie dan zou je deze altijd nog kunnen committen of rollbacken. Of je zou de transactie misschien zo kunnen parametriseren dat hij bij webapps alleen een advies uitbrengt over de commit, en bij normale toepassingen altijd comitten.

Ik ben hier zelf ook niet uit hoor :P Ik zie hier een (van de vele) gaten bij webapplicatie die gedeeltelijk of niet beantwoord worden. Dito geld voor validatie en save methodes.. oja. en ongeschreven semantiek van or-mappers en de droom dat dao`s implementatie onafhankelijk zijn (je kunt dus niet van dao implementatie wisselen).

[edit]
Ik ben in principe nog een totale noob op het 'bedrijfs applicatie' gebied. Ik doe het nu een 3 kwart jaar.. Dus veel vragen zullen in de loop der tijd wel beantwoord worden maar vind het jammer dat ik niet een lijst van problemen vind die veel andere developers (die net zo denken als ik) tegen aan lopen.

[ Voor 17% gewijzigd door Alarmnummer op 22-05-2005 12:22 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Alarmnummer schreef op zondag 22 mei 2005 @ 12:18:
[...]

Dat zelfde zou opgaan als je niet met een webapp werkt. Als je informatie terug zou krijgen over de status van de transactie dan zou je deze altijd nog kunnen committen of rollbacken. Of je zou de transactie misschien zo kunnen parametriseren dat hij bij webapps alleen een advies uitbrengt over de commit, en bij normale toepassingen altijd comitten.
Ik had het over die lazy loading:
Simpel voorbeeld: Stel, je hebt een rich-client applicatie. In die applicatie heb je een form waarop je gegevens van een klant kunt bekijken, en op een 2de tabblad kan je een historiek van z'n orders ofzo bekijken.
Stel dat die historiek niet zo vaak bekeken wordt, en dat je dit dmv lazy loading wilt implementeren.
Dan ga je dus, als je form geopend is, het gepaste 'klant' object gaan opvragen zonder z'n order-historiek.
Als je nu die historiek wilt bekijken, dan moet je 'm gaan ophalen, en dat moet in een andere 'transactie' gebeuren (al vind ik de term transactie bij een SELECT query niet echt gepast).

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 22 mei 2005 @ 12:22:
[...]

Ik had het over die lazy loading:
Simpel voorbeeld: Stel, je hebt een rich-client applicatie. In die applicatie heb je een form waarop je gegevens van een klant kunt bekijken, en op een 2de tabblad kan je een historiek van z'n orders ofzo bekijken.
Stel dat die historiek niet zo vaak bekeken wordt, en dat je dit dmv lazy loading wilt implementeren.
Als je de transactie nog openhoud zo lang de webpagina view nog niet klaar is met gerenderd worden vind ik dat niet zo`n probleem aangezien dat geen eeuwigheid zal duren. Maar op het moment dat jij het aan de gebruiker overlaat wanneer die transactie gesloten gaat worden (dus pas als die history is getekend en anders blijft die open), dan ben je denk ik, vanuit praktisch oogpunt, niet correct bezig met transacties. Je houd transacties te lang open -> te groot lock window -> performance problemen voor de server (want de db gaat zo traag als stront).

Als de history van de gebruiker getekend moet worden zou ik hiervoor weer een nieuwe transactie openen.

[ Voor 68% gewijzigd door Alarmnummer op 22-05-2005 12:30 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
^^ Dat, is wat ik wou zeggen. :)

Echter, ik vind het een beetje 'raar' om m'n transactie-handling aan de client over te laten. (Zie m'n eerste post).

[ Voor 66% gewijzigd door whoami op 22-05-2005 12:31 ]

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 22 mei 2005 @ 12:31:
^^ Dat, is wat ik wou zeggen. :)

Echter, ik vind het een beetje 'raar' om m'n transactie-handling aan de client over te laten. (Zie m'n eerste post).
Wie zegt dat je het aan de klant overlaat? Zowel de klantservice als de orderservice coordineren de transacties. Jouw 'haalklant' en jouw 'berekeninformatievoorhistogram' regelen hun eigen transacties.. de klant heeft daar 0.0 invloed op.

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Volgens mij zijn er logisch gezien gewoon 2 soorten transacties.

type 1. voor de gecombineerde classes (die 3 saves moeten doen voor alle childclasses etc..).
type 2. voor businesslogic: bijv. een order opslaan, een todo-item aanmaken (om na te bellen) en een mailtje sturen. En als een van die niet lukt, dan allemaal niet.

in programmeerboeken kan ik alleen maar terugvinden dat als het over transacties gaat, ze het hebben over type 1. Voor type 2 heb ik ook nog nergens een oplossing gelezen.

Bij het vinden van een oplossing voor type 2 vond ik het belangrijk dat in mijn datalaag geen koppelingen werden gemaakt tussen logisch-onafhankelijke onderdelen. (Bijv todo-item-datalaag moet geen afhankelijkheid krijgen op de order-data-laag en andersom. Omdat todo-items ook worden gebruikt in andere apps die geen orders gebruiken.)

Technisch gezien gaat de dataintegriteit niet naar de knoppen als er wel een 'order' in de db komt en geen 'todo-item'. Echter gezien vanuit wat het programma moet doen, is het wel een fout in de integriteit.
Om die reden is het ook niet erg om de integriteit voor type 2 transacties op business-layernivo te bewaken.

m.a.w. de door jouw gevonden oplossing is in mijn ogen helemaal geen vervuilen, maar een oplossing om de datalaag netjes te houden :) en je app flexibel.

Wat ik wel heb gemaakt zijn overloads op de save-methods zodat ze optioneel een transactie-object mee kunnen krijgen. Dan hoef je voor type 1 transacties geen transactielogica in de businesslayer te typen. Want dat hoort imho ook niet.

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

Alarmnummer

-= Tja =-

joopst schreef op zondag 22 mei 2005 @ 14:51:
Volgens mij zijn er logisch gezien gewoon 2 soorten transacties.

type 1. voor de gecombineerde classes (die 3 saves moeten doen voor alle childclasses etc..).
Dit kan ik niet plaatsen. Domain objects zullen zelf nooit een save aanroepen om zichzelf te persisten naar de db. Dat is taak van de service/business laag (grrr... onduidelijke kuttermen)
type 2. voor businesslogic: bijv. een order opslaan, een todo-item aanmaken (om na te bellen) en een mailtje sturen. En als een van die niet lukt, dan allemaal niet.

in programmeerboeken kan ik alleen maar terugvinden dat als het over transacties gaat, ze het hebben over type 1. Voor type 2 heb ik ook nog nergens een oplossing gelezen.
Type 2 is heel veel over geschreven, zoek maar eens naar service laag. De service laag is verantwoordelijk voor het coordineren van de transacties:

pseudocode voorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class BankBusinesslaag{
     void maakGeldOver(Rekening van, Rekening naar, Rekening bedrag){
        van.verwijder(bedrag);
        naar.stort(bedrag);
        _rekeningDao.save(van);
        _rekeningDao.save(naar);
}
}

class BankServiceLaag{
void maakGeldOver(Rekening van, Rekening naar, Rekening bedrag){
    transactie = new Transactie();
    transactie.start();
    try{
        _bankbusinesslaag.maakGeldOver(van,naar,bedrag)
   }catch{Exception ex){
      transactie.rollback();
   }
}
}


In dit voorbeeld heeft de bank service layer een referentie naar de bank business layer en delegeerd de werkelijke implementatie daar naar toe, maar voegt er transacties aan toe.
Bij het vinden van een oplossing voor type 2 vond ik het belangrijk dat in mijn datalaag geen koppelingen werden gemaakt tussen logisch-onafhankelijke onderdelen. (Bijv todo-item-datalaag moet geen afhankelijkheid krijgen op de order-data-laag en andersom.
idd
Wat ik wel heb gemaakt zijn overloads op de save-methods zodat ze optioneel een transactie-object mee kunnen krijgen. Dan hoef je voor type 1 transacties geen transactielogica in de businesslayer te typen. Want dat hoort imho ook niet.
In de business laag zitten geen transacties. Volgens fowler is er een super dunne laag boven de business laag, namelijk de service laag. Deze laag is verantwoordelijk voor coordineren van de transacties. In principe is het voorbeeld dat hierboven staat ook niet goed. Maar doordat het tegenwoordig mogelijk is om mbv attributen/metadata/annotations :P transactionele eigenschappen aan methodes toe te kennen, zie je dat de service laag en de business laag met elkaar integreren, vb:

code:
1
2
3
4
5
6
7
@transactioneel
void maakGeldOver(Rekening van, Rekening naar, Rekening bedrag){
   van.verwijder(bedrag);
   naar.stort(bedrag);
   _rekeningDao.save(van);
   _rekeningDao.save(naar);
}


In dit voorbeeld is er niet echt onderscheid meer tussen de business en service laag.

[ Voor 13% gewijzigd door Alarmnummer op 22-05-2005 15:09 ]


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
bij type 1 bedoelde ik de 'aggregate root' zoals door whoami beschreven.


Ik zie de servicelayer idd uitgelegd op patternshare.org

ik kende deze idd nog niet, maar nu wel :) bedankt.
voor type1 problemen is het iid een handige laag (ik ga mijn code ook maar eens refactoren)

voor type2 is het net een 1 op 1 doorgeefluik. Daar zet ik mijn vraagtekens bij of het wel iets toevoegt qua handigheid. (als dezelfde transactie vaker gebruikt wordt wel denk ik, maar dat altijd maar de vraag)

het is zo iig (voor mij) een stuk inzichtelijker geworden

[ Voor 9% gewijzigd door joopst op 22-05-2005 15:58 . Reden: beetje uitduidelijken ]


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

Alarmnummer

-= Tja =-

joopst schreef op zondag 22 mei 2005 @ 15:56:
bij type 1 bedoelde ik de 'aggregate root' zoals door whoami beschreven.


Ik zie de servicelayer idd uitgelegd op patternshare.org
Hier staat die ook:
http://www.martinfowler.com/eaaCatalog/serviceLayer.html
voor type2 is het net een 1 op 1 doorgeefluik. Daar zet ik mijn vraagtekens bij of het wel iets toevoegt qua handigheid. (als dezelfde transactie vaker gebruikt wordt wel denk ik, maar dat altijd maar de vraag)
Ik snap niet wat type 1 en 2 inhouden.
het is zo iig (voor mij) een stuk inzichtelijker geworden
Gelukkig.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Dat met die service - layer is misschien wel de beste oplossing.

Op die manier staat je BL t.a.t. op de server, en ben je beperkt in de operaties die je daarop kunt uitvoeren, want het is de service layer die die operaties beschikbaar maakt.
Wat heb je dan op je client: gewoon 'domme' objecten ?
Nadeel van dit is dan natuurlijk wel dat je met een 'chatty' interface komt te zitten denk ik. Voor iedere operatie die je wilt uitvoeren, heb je een server-call nodig.

Het voordeel van het systeem dat ik in m'n startpost heb beschreven, is dan net weer dat het toch responsiever zal zijn. Je kan je business-operaties ook op de client uitvoeren; en, door met click-once te werken beschikt je client ook altijd over de laatste versies van de business objecten.
Om dit even te illustreren:
Je hebt bv de Customer class, en deze wordt in de client gebruikt.
De CustomerProvider wordt ook in de client gebruikt, en die gaat de Customer gaan saven:

min of meer pseudocode
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 CustomerProvider : MarshalByRefObj
{
  public void Save( Customer c )
  {
       transaction.Start();
       
       try
       {
             customerGateway = gatewayFactory.CreateCustomerGateway();
             customerGateway.Save (transaction, c);

             orderGateway = gatewayFactory.CreateOrderGateway();
             foreach( Order o in c.Orders )
             {
                  orderGateway.Save (o);
             }

             transaction.Commit();

       }
       catch( Exception ex )
       {
          transaction.Rollback();
       }
  }
}


M'n Customer en Order objecten leven dus zowel op de server als op de client; m'n CustomerProvider is een remoted object, en die controleert de transacties.

Echter, dit is te beperkt.
Stel nu dat ik een situatie heb waarbij ik geld van één rekening naar een andere wil kunnen overschrijven. Dan heb ik een transactie nodig die over 2 'Account' objecten gaat.
Dit kan ik niet met bovenstaande oplossing oplossen, maar dan heb ik idd iets nodig zoals Alarmnummer al illustreerde, een Service-Layer. Maarja, dan zit ik met een chatty interface.
Misschien moet ik maar beiden combineren....
Voor gevallen zoals het overschrijven een soort van Services maken, en voor de andere stuff m'n eerste idee volgen.

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 22 mei 2005 @ 16:31:
Dat met die service - layer is misschien wel de beste oplossing.

Op die manier staat je BL t.a.t. op de server, en ben je beperkt in de operaties die je daarop kunt uitvoeren, want het is de service layer die die operaties beschikbaar maakt.
Wat heb je dan op je client: gewoon 'domme' objecten ?
Nadeel van dit is dan natuurlijk wel dat je met een 'chatty' interface komt te zitten denk ik. Voor iedere operatie die je wilt uitvoeren, heb je een server-call nodig.
Als het op zichzelfstaande transactionele acties zijn, dan wel ja. Maar ik betwijfel of je nu zoveel losse acties krijgt. Ik ben verder ook (nog) geen guru in de remoting problematiek en de bijbehorende dto semantiek.
Het voordeel van het systeem dat ik in m'n startpost heb beschreven, is dan net weer dat het toch responsiever zal zijn. Je kan je business-operaties ook op de client uitvoeren; en, door met click-once te werken beschikt je client ook altijd over de laatste versies van de business objecten.
Je kunt toch gewoon clientside al je dto`s in de juiste toestanden brengen en deze toestand doorsturen naar de server met het verzoek: wil je dit aub ff verwerken. Aan de serverkant kan je de dto`s wel uit elkaar pluizen en de bijbehorende acties op laten uitvoeren.
Alarmnummer al illustreerde, een Service-Layer. Maarja, dan zit ik met een chatty interface.
Ik zie die chatty interface niet.En volgens mij trek jij veel te veel logica naar de client toe. Met mijn huidige kennis zou ik zeggen: zet die dto`s in de volgende toestand en stuur dat door naar de server (in 1 slag). De server die kan al jouw voorgestelde bewerkingen (die versleuteld liggen in de dto`s) onder 1 enkele transactie uitvoeren.

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Je kan in de servicelayer ook methods maken die zoveel parameters accepteren dat je wel chuncky kan communiceren.

Die chunkcy methods roepen op de server dan al die chatty methods aan.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op zaterdag 21 mei 2005 @ 22:41:
Allemaal goed en wel, in dit geval zou je kunnen zeggen dat de Transactie-handling (start-transaction call, commit en rollback call) in de CustomerProvider thuis horen.
Nou, dat denk ik niet. De customerprovider 'participeert' in een transaction die je instantieert met een Transaction object, en waaraan je die customerprovider toevoegt.
Echter, in bepaalde situaties is dit niet voldoende. Soms kan het zijn dat ik mijn transactie over meer dan één 'aggregate root' wil laten lopen.
Mooi he, dat DDD ;)
Daarom zou het dus eigenlijk het beste zijn dat ik mijn 'client' verantwoordelijk laat zijn voor het starten / committen / rollbacken van transacties.
Echter, dan is nu mijn vraag hoe ik dat het best doorgeef aan m'n providers...

Ik kan dat natuurlijk wel zo doen:
code:
1
2
3
4
5
6
transactionSession = App.BeginTransaction();

customerProvider.Save (transactionSession, customer);
customerProvider.Save (transactionSession, customer2);

transactionSession.Commit();


Echter, dan 'vervuil' ik m'n client wel met dat transactie-gedoe, maar ik zie niet in hoe het anders kan.
Ik heb dan ook wel een extra parameter in m'n Save method die het boeltje er imho ook niet echt duidelijker op maakt.
Iemand die hier een goed idee over heeft ?
Een extern transaction object gebruiken, en alle providers een interface laten implementeren, en ze toevoegen aan je transaction, dus:
transactionSession.Add(customerProvider);
customerProvider.Save(customer);

Op dat moment gebruikt customerProvider de transaction waaraan hij is toegevoegd. Is hij niet toegevoegd aan een transaction? dan maakt hij zelf een aan, mocht dat nodig zijn. Opgelost! :)

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


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
EfBe schreef op zondag 22 mei 2005 @ 19:19:
[...]

Een extern transaction object gebruiken, en alle providers een interface laten implementeren, en ze toevoegen aan je transaction, dus:
transactionSession.Add(customerProvider);
customerProvider.Save(customer);

Op dat moment gebruikt customerProvider de transaction waaraan hij is toegevoegd. Is hij niet toegevoegd aan een transaction? dan maakt hij zelf een aan, mocht dat nodig zijn. Opgelost! :)
Hmm, alleszins een mooiere oplossing dan die oplossing die ik in m'n hoofd had om een transactie-object door te geven aan de provider. (In dat geval had ik dus een Save method zonder transaction object, en een overloaded Save method met transaction object).

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Alarmnummer schreef op zondag 22 mei 2005 @ 07:08:
Ik heb mijn buik er eerlijk gezegd behoorlijk van vol. Wat is trouwens wel een redelijk handige techniek vind hier is een "ignore where sentence contains martin fowler"
:D Ik ben het met je eens hoor, wat ik me alleen afvraag: was jij niet een van de die-hard DDD-ers hier? :)

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


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

Alarmnummer

-= Tja =-

EfBe schreef op zondag 22 mei 2005 @ 20:27:
[...]
:D Ik ben het met je eens hoor, wat ik me alleen afvraag: was jij niet een van de die-hard DDD-ers hier? :)
In het begin was Patterns of Enterprise Application architecture een openbaring voor me en er staat ook veel goeds in. Maar ik heb er een hekel aan als er tig namen zijn voor bepaalde componenten en iedereen ze weer een andere indeling geeft. En ze veel dingen als slecht bestempelen met 'dit is de manier waarop het niet moet'. Maar ze dan niet goed uitleggen hoe het wel moet. Soms nog wel in grote lijnen, maar belangrijke nieuwe problemen, die voortvloeien uit de nieuwe aanpak, negeren. En verder heb ik ook hekel aan (en verlies ik vertrouwen) op het moment dat bepaalde argumenten om voor een aanpak te gaan, in de praktijk niet kloppen. Kijk bv naar het argument om dao`s zo op te stellen dat je van implementatie kan wisselen. Bullshit.. je bent gebonden aan allerlei ongeschreven regels van ormappers. Als je snel wilt werken. maak je gebruik van de volledige mogelijkheden van de ormapper.

Ik heb niets tegen complexe oplossingen, maar oplossingen waar ik het vertrouwen in kwijt raak omdat belangrijke vragen niet gesteld en beantwoord worden, neem ik niet serieus. En zeker niets voor zoiets vaak gebruikt als de 'enterprise' problematiek.

En verder hangt de keuze van bepaalde oplossingen ook af van de complexiteit van de applicatie. In het begin probeer je alles op de 'zo hoort het' manier te doen. Maar op den duur ben je je dood aan het bladeren in de sources. Ik heb nu maar een kogel door mijn kerk gejaagd.. ok.. fuck de 'dit hoort zo' manier. We doen het nu op mijn manier (uiteraard wel geinspireerd door hetgeen wat ik heb gelezen), maar heb geen zin om steeds voor jan kut een hele lading extra werk te verzetten. En verder ben ik flauw van de onzekerheid.. iedereen beweert iets anders.. altijd valt er wel iets op je code aan te merken..

[edit]
En als de het bouwen van dit gedeelte van de applicatie nou zo interessant en uitdagend was dan had ik er niet zoveel problemen mee. Maar het iedere keer hetzelfde, alleenin een nieuw jasje, nieuwe namen, nieuwe problemen opgelost en nieuwe problemen gecreeerd. Veel enterprise problematiek (en dan doel ik op de zoveelste webapplicatie) is gewoon harstikke saai, want vaak zijn nieuwe oplossingen niets anders dan een verschuiving van verantwoordelijkheden.

[edit2]
Wil je mijn interesse wekken binnen de enterprise problematiek dan zul je toch met iets beters moeten aankomen. Mooi stuk concurrency problematiek met eventueel een flinke dosis asynchrone communicatie of realtime eisen, daar word ik bv wel erg blij van.

[ Voor 63% gewijzigd door Alarmnummer op 22-05-2005 21:17 ]


  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 09-01 10:13

MaxxRide

Surf's up

Daar heb ik ook aan gedacht, maarja, wat als je nu binnen één transactie 2 of meer objecten wilt opslaan die eigenlijk van een ander type zijn ?
Schijnbaar heb je dit nodig in je business model, ik zou dan zeggen een soort composite class met daarin een of meerdere root aggregates die binnen een transactie vallen. Je krijgt dan dus een submodel verantwoordelijk voor composites en transacties met betrekking tot die composite. Dat is toch eigenlijk wat een root aggregate ook doet (root-aggregate is alleen + want hij doet iets meer).

If you are not wiping out you are nog pushing enough...


  • D4Skunk
  • Registratie: Juni 2003
  • Laatst online: 20-10-2025

D4Skunk

Kind of Blue

Ok, mijn .02 €

Domain driven development is mooi, maar brengt vanzelfsprekend extra werk mee.. imho kan je niet zonder die extra servicelayer voor je transacties.

Wat ik zelf eens zou willen implementeren - ik heb het dus nog niet gedaan omwille van tijdsgebrek -, is een servicelayer dmv scripting. Dan heb je volgens mij het beste van twee werelden :
- je definiëert je DataLayer en business layer (met bijbehorende constraints etc) in je standaard taal (c# in jouw geval waarschijnlijk).
- interactie tussen de data/business layer en gebruiker gebeurt dmv workflow definitie/state machines en een dynamisch gegenereerde wizard ui in een scripting taal.
- Verder is er nog een geavanceerde 'directe' grid-based toegang tot de db voor de powerusers.

Wat ik persoonlijk een zeer interessant project vond, is/was compiere; zij gingen nog wel een stapje te ver imho mbt tot programmadynamiek, maar het is/was wel een goed project om ideeën op te doen...

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

Alarmnummer

-= Tja =-

D4Skunk schreef op maandag 23 mei 2005 @ 11:16:
Ok, mijn .02 €

Domain driven development is mooi, maar brengt vanzelfsprekend extra werk mee.. imho kan je niet zonder die extra servicelayer voor je transacties.

Wat ik zelf eens zou willen implementeren - ik heb het dus nog niet gedaan omwille van tijdsgebrek -, is een servicelayer dmv scripting.
Wat zijn de taken van de door jouw gebruikte definitie van service layer? (aangezien er meerdere definities in omloop zijn).

De door mij gebruikte definitie is een dunne laag die voornamelijk transacties en security regels. En dit kan je tegenwoordig ook vrij goed door dmv metadata toevoegingen (soms direct in de taal) en soms in script bestanden (een van de mogelijkheden bij Spring). Dus ik zie niet in wat hier te scripten valt.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
D4Skunk schreef op maandag 23 mei 2005 @ 11:16:
Domain driven development is mooi, maar brengt vanzelfsprekend extra werk mee.. imho kan je niet zonder die extra servicelayer voor je transacties.
Je hebt het hier over de Service Layer die Alarmnummer in één van z'n eerste posts aanhaalde ?
Een layer waarin je eigenlijk de 'toegestane operaties' definieert ?

Wat gebruik je dan in je GUI ? Gebruik je dan 'domme' objecten die enkel data bevatten, en geef je die dan door aan je service layer ? Je service layer (die op de server zit) vertaalt die dan naar business objecten ?

https://fgheysels.github.io/


  • D4Skunk
  • Registratie: Juni 2003
  • Laatst online: 20-10-2025

D4Skunk

Kind of Blue

@ alarmnummer en whoami :

Misschien is service layer niet echt de goede benaming :)
Met die scripting layer bedoelde ik eigenlijk de klassieke workflow-implementatie.
Pseudocode (niet echt over nagedacht, dus er zullen wel wat hiaten inzitten):

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Workflow ProcessOrder :
  Constant VIPSALESAMOUNT : 
    100000
  Constant MAXOPENDEBT :
    10000
  Condition OrdersToProcess None: 
        .Count==0 
  Condition CurrentCustomer NoOrderAllowed:
        .Blacklisted
        OR
        Sum(.Invoices,Debt)>MAXOPENDEBT
  Condition CurrentCustomer IsVIP:
        Sum(.Sales,Total)>VIPSALESAMOUNT
  State Load :
       OrdersToProcess=Db.Orders.ToProcess(LockNone)
       SaveCurrentState("initial")
       if OrdersToProcess.None NextState =FinishedWithoutErrors         
       NextState=CheckOrders
  State CheckOrders :
       Screen.Clear
       chkOrders=Screen.Add(CheckList,OrdersToProcess, .Customer.Name+" " + Sum(.Orderlines.,total))
       Screen.Show 
       ...


etc...
Terwijl ik dit vb opgesteld heb, stel ik mezelf al een paar vragen bij dit hele concept, maar toch blijf ik erbij dat dit wel eens de moeite waard zou zijn om dit te implementeren.
De klassieke business methods (berekeningen etc) moeten in je business layer zitten en vanuit het script toegankelijk zijn, en je datalayer zit apart en is dan via een repository toegankelijk
al je binding tussen datalayer/ui/business layer zou dan in deze scripting laag gebeuren.

Trouwens een positieve ontwikkeling voor .Net 3.0 imho is de richting die C omega op dit moment volgt... geintegreerde sql etc... dan moeten we al die layers niet meer schrijven. LOL
Tenminste, dat hoop ik :P

Edit:
Misschien zou het beter zijn om die condities op te nemen in je business layer, maar dan kan je natuurlijk geen aggregate functies gebruiken he ;)

[ Voor 6% gewijzigd door D4Skunk op 23-05-2005 13:21 ]


  • D4Skunk
  • Registratie: Juni 2003
  • Laatst online: 20-10-2025

D4Skunk

Kind of Blue

*kick* ik vind dit eigenlijk wel een interessant topic....

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Ik kom hier even op terug.

Nu geef ik een 'transaction-handler' (bv een NHibernate isession object) door aan m'n Repository.
Echter, ik heb zitten denken:
wat als ik nu een begintransaction/committransaction method toevoeg aan de interface van mijn repositories ? Dit zou er natuurlijk voor zorgen dat mijn repositories statefull zullen zijn tussen method calls. (Ze zullen nl. de state van de transactie moeten weten).
Is dit een goed idee ?

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

Uhh.. wat moet die dao met die transaction handler?

Ik heb mijn sessie gebonden aan een threadlocal zodat de dao er bij kan komen. En verder coordineer ik de transacties (die hebben die sessie ook nodig) vanuit de service layer en niet vanuit de dao`s want die horen daar geen weet van te hebben. Ik snap niet helemaal hoe ik repositories in dit plaatje moet zien.

Ik ben verder ook niet echt voor statefull objecten. Je moet dan objecten per thread maken (zodat je geen conflicten gaat krijgen) of je krijgt een zooi concurrency control voor de kiezen.

[edit]
Ik snap niet helemaal hoe ik repository in dit plaatje moet zien *is al een tijd geleden dat die naar het boek van fowler heeft gekeken*

[ Voor 26% gewijzigd door Alarmnummer op 28-08-2005 18:53 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Een 'Repository' kan je zien as een 'object' die verantwoordelijk is om de domein-objecten op te halen / persisten naar een persistence source.
Zo'n repository kan er zo uit zien:
code:
1
2
3
4
5
6
7
8
9
10
11
public class CustomerRepository
{
     public Customer NewCustomer()
     {
        //
     }

      public Customer GetCustomer( int customerId ) {}
    
      public void SaveCustomer( Customer c) {}
}


Waarom die repository een 'transaction-handler' moet hebben/meekrijgen, is gewoon omdat die repository zich niet met transacties mag moeien. De client van mijn repository (de applicatie, een service-laag, whatever), weet de context van die transacties. Het is de client dus, die weet wat er in één transactie thuishoort. (Stel dat ik -dom voorbeeld- 2 klanten in eenzelfde transactie wil saven).
Daarom zou ik dus een 'transaction-handler' object meegeven aan die SaveCustomer method, of, zou ik een BeginTransaction etc... method maken op m'n repository.

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 28 augustus 2005 @ 19:01:
Een 'Repository' kan je zien as een 'object' die verantwoordelijk is om de domein-objecten op te halen / persisten naar een persistence source.
Zo'n repository kan er zo uit zien:
code:
1
2
3
4
5
6
7
8
9
10
11
public class CustomerRepository
{
     public Customer NewCustomer()
     {
        //
     }

      public Customer GetCustomer( int customerId ) {}
    
      public void SaveCustomer( Customer c) {}
}
Dao dus :P Ik had het boek er nog even bijgepakt en het is idd de Dao.
Waarom die repository een 'transaction-handler' moet hebben/meekrijgen, is gewoon omdat die repository zich niet met transacties mag moeien.
Met het laatste ben ik het eens, ik zie alleen niet in waarom het 1e daarvan het gevolg moet zijn.
De client van mijn repository (de applicatie, een service-laag, whatever), weet de context van die transacties. Het is de client dus, die weet wat er in één transactie thuishoort. (Stel dat ik -dom voorbeeld- 2 klanten in eenzelfde transactie wil saven).
Mee eens.
Daarom zou ik dus een 'transaction-handler' object meegeven aan die SaveCustomer method, of, zou ik een BeginTransaction etc... method maken op m'n repository.
Ik zou die repository sowieso al niet statefull maken. Als jij werkt met Hibernate dan zul je ook vast wel een sessie tot je beschikking hebben. Je moet er voor zorgen dat deze sessie aan de threadlocal is gebonden zodat je repository erbij kan (hoef je dat ding niet de hele tijd mee te slepen).

En verder kan je over je sessie die transactie plakken in je service layer. Dus ik zie het nut nog steeds niet van die TransactieHandler..

pseude:

code:
1
2
3
4
5
6
7
Sessie sessie = sessieFactory.createSessie();
SessieThreadLocal = sessie;

Transaction t = sessie.startTransaction();
..jouw business logica met oa`s dao/repository calls.
t.commit();
sessie.close();

[ Voor 8% gewijzigd door Alarmnummer op 28-08-2005 19:35 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Eerst ff dit: De benaming 'transaction-handler' die ik hanteerde, is een 'conceptuele' naam. Het is geen naam van een of andere bestaande class ofzo.
Ik ben het met je eens dat ik via mijn ISession van (N)Hibernate aan m'n transactie kan. In het voorbeeld dat ik eerder hanteerde, zou ik dus concreet gezien, m'n ISession aan m'n repository meegeven.
Alarmnummer schreef op zondag 28 augustus 2005 @ 19:34:
[...]

Met het laatste ben ik het eens, ik zie alleen niet in waarom het 1e daarvan het gevolg moet zijn.
Ik zou vragen: 'hoe geef jij dan je sessie dan door?', maar even verder staat je antwoord: je hangt het aan de 'threadlocal'. Hoe doe jij dit dan ? Ik stel me voor dat dit iets Java-specifieks is ?
Ik zou nl. niet weten hoe ik zoiets in .NET kan voor elkaar krijgen.
Zoals ik jouw reply lees, stel ik mij voor dat je bv zo iets zou doen:
code:
1
CurrentThread.StateHolderBliep = session;

Echter, in .NET heb ik geen member van 'Thread' waar ik zelf een custom object of whatsoever kan aan meegeven.

En dan dit: dan moet jij toch nog iedere keer de sessie aan die thread gaan hangen als je een method op je dao/repository/whatsoever aanroept ?

https://fgheysels.github.io/


  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 27-04 18:17

gorgi_19

Kruimeltjes zijn weer op :9

whoami schreef op zondag 28 augustus 2005 @ 20:20:
Ik zou vragen: 'hoe geef jij dan je sessie dan door?', maar even verder staat je antwoord: je hangt het aan de 'threadlocal'. Hoe doe jij dit dan ? Ik stel me voor dat dit iets Java-specifieks is ?
Ik zou nl. niet weten hoe ik zoiets in .NET kan voor elkaar krijgen.
Bedoel je iets als http://www.dotnetcoders.c...owArticle.aspx?article=58 ?

Digitaal onderwijsmateriaal, leermateriaal voor hbo


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Idd; dus toch. :P
Daar was die GetData/SetData dus voor. * whoami zag ze in de help voorbij-komen, maar heeft ze niet in detail bekeken. :+

Iig, als ik het zo zou doen, dan zou dit toch alsnog willen zeggen dat ik iedere keer dit zou moeten doen:
code:
1
2
3
4
5
6
ISession theSession = SessionFactory.OpenSession();
Thread.CurrentThread.SetDate ("session", theSession);
ITransaction trans = theSession.BeginTransaction();
CustomerRepository.SaveCustomer ( c );
CustomerRepository.SaveCustomer2( c2 );
trans.Commit();

Waarom dan niet gewoon:
code:
1
2
3
4
5
ISession session = ...
ITransaction trans = session.BeginTrans();

CustomerReposity.SaveCustomer (trans, c);
trans.Commit();


En waarom dan niet:
code:
1
2
3
CustomerRepository.BeginTransaction();
CustomerRepository.SaveCustomer (c);
CustomerRepository.SaveTransaction();

In dit geval laat je het transactie-gebeuren ook aan de client over, maar is heel dat session - gedoe ook meteen afgeschermd.
In de BeginTransaction() method van de Repository kan je dan een sessie creeëren en een transactie starten, etc...

[ Voor 18% gewijzigd door whoami op 28-08-2005 20:31 ]

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 28 augustus 2005 @ 20:29:
Iig, als ik het zo zou doen, dan zou dit toch alsnog willen zeggen dat ik iedere keer dit zou moeten doen:
Dingen mooier maken kan altijd nog. Ik zou me nu vooral concentreren op een goeie structuur.

Trouwens.. als je met Hibernate aan de slag gaat, dan kom je zeker in aanraking met lazy structuren (lazy collections bv). Dit heeft voordelen, want anders zou je bv als je adam uit de db haalt, de hele mensheid uit de db trekken. Maar dit heeft ook nadelen. Stel dat je een lazy set met kinderen hebt, dan maakt Hibernate een proxy aan waarin de sessie zit waarop de 'hoofd'objecten werden opgehaald. Stel dat ik dan vraag: adam.getKinderen(), en die kinderen zijn nog niet ingeladen, dan wordt die sessie gebruikt om ze alsnog op te halen. Ok. tot zover de uitleg van het lazy gedeelte.

Maar wat nu als je bv een gui hebt waarin de kinderen van adam nodig zijn? Die sessie is al lang gesloten want de transactie is afgelopen. Dit kan een vrij vervelend probleem zijn om goed te krijgen want je manier van aanpak heeft bepaalde consequenties.

[ Voor 65% gewijzigd door Alarmnummer op 28-08-2005 21:10 ]


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

ik reageer ff op de code in de TopicStart, met een opmerking/vraagje:

Ikzelf heb vorig jaar een programma geschreven en ik deed het zo:
C#:
1
2
3
MijnObject x = provider.getMijnObject(zus,zo)
// doe iets met x
x.save()


de provider stelde dan voor het returnen, de gemeenschappelijke data laag op het object x.
x was dan verantwoordelijk voor het saven van zichzelf en zijn members, die op zich ook verantwoordelijk waren voor zichzelf en hun members etc...

Is er een fout in deze aanpak van mij of maakt het an sich niet veel uit?

ASSUME makes an ASS out of U and ME


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

Alarmnummer

-= Tja =-

HIGHGuY schreef op zondag 28 augustus 2005 @ 21:13:
Is er een fout in deze aanpak van mij of maakt het an sich niet veel uit?
Het grootste probleem aan deze aanpak is dat je domein object dus verschillende vormen van logica gaat herbergen. Een gedeelte van de domain logica zit erin (alhoewel ik eerlijk toe moet geven dat er over het algemeen echt bijna niets in zit). En verder zit er dan uiteraard de persistence logica in. Uiteindelijk kunnen er nog wel meer aspecten van je systeem in die objecten terecht komen, maar dan krijg je lompe structuren met alle gevolgen van dien.

Ik vind het zelf wel prettig om dit uit elkaar te trekken en om alle logica mbt het persisten van objecten in een dao onder te brengen. Ik kan daar saven (zoals jij op je x.save() doet), maar ik kan ook loaden/finden etc (hoe wou je dit onderbringen bij die instantie)? Ik wil niet zeggen dat de structuur perfect is, maar hij is wel erg goed werkbaar.

Algemene opmerking:
de afgelopen jaren is er erg veel geschreven over dit onderwerp en ik kan niets anders concluderen dat hetgeen dat in boeken staat in de praktijk vaak niet te realiseren is. Soms heb ik de indruk dat de mensen die de boeken schrijven zelf geen ervaring ermee hebben. Ik zit veel op het Spring forum en het kennis gehalte is daar behoorlijk hoog en daar kan niemand bruikbare antwoorden geven hoe het nu precies moet. Dus ik heb ook zoiets van.. up yours.. als het werkt en onderhoudbaar is... dan is het goed genoeg voor mij.

[ Voor 7% gewijzigd door Alarmnummer op 28-08-2005 21:25 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:06:
[...]

Maar wat nu als je bv een gui hebt waarin de kinderen van adam nodig zijn? Die sessie is al lang gesloten want de transactie is afgelopen. Dit kan een vrij vervelend probleem zijn om goed te krijgen want je manier van aanpak heeft bepaalde consequenties.
Uhuh... Ik zie het probleem.... Maar de oplossing niet. :o
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:23:
[...]

Algemene opmerking:
de afgelopen jaren is er erg veel geschreven over dit onderwerp en ik kan niets anders concluderen dat hetgeen dat in boeken staat in de praktijk vaak niet te realiseren is. Soms heb ik de indruk dat de mensen die de boeken schrijven zelf geen ervaring ermee hebben. Ik zit veel op het Spring forum en het kennis gehalte is daar behoorlijk hoog en daar kan niemand bruikbare antwoorden geven hoe het nu precies moet. Dus ik heb ook zoiets van.. up yours.. als het werkt en onderhoudbaar is... dan is het goed genoeg voor mij.
:o
Dat idee heb ik ook wel eens. Soms zie je iets in boeken; en wat er in staat uitgelegd en beschreven klinkt allemaal goed, maar als je dan wat verder gaat nadenken, of iets probeert, dan merk je dat het toch wel ergens stroef loopt.
Of: soms heb je wel voorbeeldjes in die boeken, maar bepaalde dingen in die voorbeelden mis ik dan toch. Bepaalde dingen die ik best belangrijk vind, en waar ik dan een hele tijd op zit te denken. Dan heb ik ook zo het gevoel van: de auteur heeft het er zeker uitgelaten omdat hij zelf geen goede oplossing/manier wist, of omdat hij het te lastig vond om er zelf iets goeds van te maken.

[ Voor 60% gewijzigd door whoami op 28-08-2005 21:30 ]

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
HIGHGuY schreef op zondag 28 augustus 2005 @ 21:13:


Is er een fout in deze aanpak van mij of maakt het an sich niet veel uit?
Zoals Alarmummer al zei: je gaat dan bepaalde code in je domein-object gaan zetten die daar eigenlijk niet thuis hoort.
Je domein object zou eigenlijk enkel (business)logica over het probleem domein mogen bevatten, en hoeft eigenlijk niet te weten hoe die precies weggeschreven wordt.

Het CSLA.NET framework van Rockford Lothka gebruikt echter ook die aanpak die jij gebruikt, maar ik zelf hou daar niet echt van.
Waar ik nog minder van hou, is dat dat CSLA.NET framework de transaction-handling ook in z'n domein-objecten heeft zitten: dus, niet enkel de persistence logica zit daarin, ook de begin- en commit/rollback transaction statements zitten in de 'save' method.

[ Voor 30% gewijzigd door whoami op 28-08-2005 21:33 ]

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 28 augustus 2005 @ 21:28:
[...]
Uhuh... Ik zie het probleem.... Maar de oplossing niet. :o
Voor webapplicaties trek ik een sessie open op het moment dat de request begint en doe hem dicht op het moment dat de request is afgelopen. Verder mag je nog wel doorgaan op een sessie als de transactie is afgelopen en daardoor kan je dus na je business logica (en de afgeronde transactie) nog steeds informatie ophalen uit de db. Een ander voordeel aan deze aanpak is dat je van 1 entiteit nooit meer dan 1 instantie terug kunt krijgen. Deze techniek staat ook bekend onder de open session in view.

De afgelopen maanden zijn we erg behoorlijk intensief mee bezig geweest en het is dat ik al kaal ben, maar anders had ik me de haren uit mijn hoofd getrokken. Ik heb zo nu en dan mijn twijfels over Hibernate. Het zal intern misschien wel een mooi product zijn, maar guidelines om ermee te werken zijn er niet. Boeken en documentatie laten je volledig in de steek op het moment dat je echt wilt begrijpen hoe het zit. En het forum is bevolkt met volslagen debielen en mijn vertrouwen om daar vragen beantwoord te krijgen is ook gedaald tot een volledig 0 punt. Persoonlijk beschouw ik Hibernate een bron van veel problemen en als je niet de mogelijkheid hebt om mensen te kunnen aanspreken die je uit de problemen kunnen helpen (en die komen er geheid als je er serieus mee aan de slag wilt) dan zou ik maar rekening houde met vorse tijdsoverschreidingen van je projecten.

Als ik dit allemaal geweten had, dan had ik me wel 2 keer bedacht om Hibernate te gaan gebruiken.

[ Voor 16% gewijzigd door Alarmnummer op 28-08-2005 21:38 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:34:
[...]

Voor webapplicaties trek ik een sessie open op het moment dat de request begint en doe hem dicht op het moment dat de request is afgelopen.
Tja, bij web-apps kan je dat doen, omdat je pagina eigenlijk slechts een bepaalde life cycle heeft (begin - request / end - request), en daartussen gebeurt al hetgeen wat jij wilt doen.
Bij een rich-client application is dat echter een probleem....
Ik heb zo nu en dan mijn twijfels over Hibernate. Het zal intern misschien wel een mooi product zijn, maar guidelines om ermee te werken zijn er niet. Boeken en documentatie laten je volledig in de steek op het moment dat je echt wilt begrijpen hoe het zit. En het forum is bevolkt met volslagen debielen en mijn vertrouwen om daar vragen beantwoord te krijgen is ook gedaald tot een volledig 0 punt.
Atm ben ik 'Hibernate in Action' aan het lezen, het is dan wel gericht op Java/Hibernate, maar voorlopig kom ik er wel door. (Al kruipt er wel weer een hoop tijd in :/ ).
Echter, andere goede tutorials/boeken heb ik ook nog niet gevonden.
Maar dat is eigenlijk een andere discussie :P
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:34:
[...]
Als ik dit allemaal geweten had, dan had ik me wel 2 keer bedacht om Hibernate te gaan gebruiken.
Je kan natuurlijk ook alle data-retrieval/save/mapping zelf gaan schrijven, maar dan ben je ook weer bezig...

[ Voor 12% gewijzigd door whoami op 28-08-2005 21:40 ]

https://fgheysels.github.io/


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

Alarmnummer

-= Tja =-

whoami schreef op zondag 28 augustus 2005 @ 21:38:
Atm ben ik 'Hibernate in Action' aan het lezen, het is dan wel gericht op Java/Hibernate, maar voorlopig kom ik er wel door.
Van alle Hibernate boeken is dat op dit moment het beste. Het boek van Addison Wesley is een totale aanfluiting, O`Reilly boeken zijn meestal erg licht (en dus niet geschikt voor goed inzicht) en Wrox schijnt ook een nieuw boek te hebben die behoorlijk wordt afgekraakt (iedereen verwijst ook naar Hibernate in Action).
(Al kruipt er wel weer een hoop tijd in :/ ).
Ach man..breek me de bek niet open. Ik en een collega (wij zijn verantwoordelijk voor de technische beslissingen) zijn er erg lang mee bezig geweest. Op het moment dat 1 ding werkt, storten 2 dingen weer in en maakt het toevoegen van een 3e nog een stuk lastiger. We zijn uiteindelijk op iets bruikbaars uitgekomen maar er zitten nog wel een paar gaten in. Ik heb nu eindelijk het gevoel iets te hebben waarover ik kan redeneren en uitspraken kan doen (vind ik imho extreem belangrijk als je de verantwoording hebt over de techniek).
Je kan natuurlijk ook alle data-retrieval/save/mapping zelf gaan schrijven, maar dan ben je ook weer bezig...
Zie ik eruit als iemand die gek is? Een andere or mapper waar ik de laatste tijd goeie verhalen van heb gehoord is Cayenne. Schijnt stuk eenvoudiger en duidelijker te zijn dan Hibernate. Alleen stond me niet aan dat je domain objecten een bepaalde interface moeten implementeren (niemand heeft iets te zeggen over mijn domain objecten).

ps:
90% van onze problemen komen trouwens voort uit de sessie/open sessie in view/detached/attached/transient objecten problematiek.

[ Voor 6% gewijzigd door Alarmnummer op 28-08-2005 21:47 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
whoami schreef op zondag 28 augustus 2005 @ 20:29:
[...]


En waarom dan niet:
code:
1
2
3
CustomerRepository.BeginTransaction();
CustomerRepository.SaveCustomer (c);
CustomerRepository.SaveTransaction();

In dit geval laat je het transactie-gebeuren ook aan de client over, maar is heel dat session - gedoe ook meteen afgeschermd.
In de BeginTransaction() method van de Repository kan je dan een sessie creeëren en een transactie starten, etc...
Dit systeem is toch niet goed; als ik bv een Customer en een object van een ander type binnen dezelfde transactie wil opslaan, dan zit ik weer met de gebakken peren.

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:06:
[...]
Trouwens.. als je met Hibernate aan de slag gaat, dan kom je zeker in aanraking met lazy structuren (lazy collections bv). Dit heeft voordelen, want anders zou je bv als je adam uit de db haalt, de hele mensheid uit de db trekken. Maar dit heeft ook nadelen. Stel dat je een lazy set met kinderen hebt, dan maakt Hibernate een proxy aan waarin de sessie zit waarop de 'hoofd'objecten werden opgehaald. Stel dat ik dan vraag: adam.getKinderen(), en die kinderen zijn nog niet ingeladen, dan wordt die sessie gebruikt om ze alsnog op te halen. Ok. tot zover de uitleg van het lazy gedeelte.
Lijkt me geweldig in een remoting architectuur of in een n-tier app waar de GUI geen data mag laden maar de BL moet vragen.... NOT.
Maar wat nu als je bv een gui hebt waarin de kinderen van adam nodig zijn? Die sessie is al lang gesloten want de transactie is afgelopen. Dit kan een vrij vervelend probleem zijn om goed te krijgen want je manier van aanpak heeft bepaalde consequenties.
Precies, en daarom moet je dus die aanpak alleen in bepaalde gevallen gebruiken, bv wanneer je weet dat de data niet een tier gaat verlaten.
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:34:
De afgelopen maanden zijn we erg behoorlijk intensief mee bezig geweest en het is dat ik al kaal ben, maar anders had ik me de haren uit mijn hoofd getrokken. Ik heb zo nu en dan mijn twijfels over Hibernate. Het zal intern misschien wel een mooi product zijn, maar guidelines om ermee te werken zijn er niet.
De nhibernate code intern is om te janken, en veelal 1:1 geport van de hibernate code, maar dat neemt niet weg dat de hibernate 3 code (nhibernate is op 2 gebaseerd) wel veel functionaliteit kent.
Boeken en documentatie laten je volledig in de steek op het moment dat je echt wilt begrijpen hoe het zit. En het forum is bevolkt met volslagen debielen en mijn vertrouwen om daar vragen beantwoord te krijgen is ook gedaald tot een volledig 0 punt. Persoonlijk beschouw ik Hibernate een bron van veel problemen en als je niet de mogelijkheid hebt om mensen te kunnen aanspreken die je uit de problemen kunnen helpen (en die komen er geheid als je er serieus mee aan de slag wilt) dan zou ik maar rekening houde met vorse tijdsoverschreidingen van je projecten.

Als ik dit allemaal geweten had, dan had ik me wel 2 keer bedacht om Hibernate te gaan gebruiken.
Data-access systemen moeten allemaal, ongeacht welke je neemt, gebruikt worden zoals ze gebruikt dienen te worden. Mijn ervaring is dat de mensen die moeite hebben met het gebruiken van een O/R mapper, de mapper anders WILLEN gebruiken dan hoe deze bedoelt is: ze zitten zichzelf en de mapper in de weg en de tool wordt een hindernis ipv een tool.

An sig is data-access niet zo moeilijk in gebruik: je hebt data consumers en data producers en een bak waar alles in terecht komt. Ipv de o/r mapper als kern van je app te gaan zien, is het veelal zaak de o/r mapper als middel te zien om data consumers met data producers in contact te brengen en beide te laten samenwerken met die bak waar alles in zit. Meer IS het nl. niet. Je kunt er veel meer van WILLEN maken, maar dat is de tool weer gebruiken in een andere context dan waarvoor het is bedoeld.
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:45:
[...]
Ach man..breek me de bek niet open. Ik en een collega (wij zijn verantwoordelijk voor de technische beslissingen) zijn er erg lang mee bezig geweest. Op het moment dat 1 ding werkt, storten 2 dingen weer in en maakt het toevoegen van een 3e nog een stuk lastiger. We zijn uiteindelijk op iets bruikbaars uitgekomen maar er zitten nog wel een paar gaten in. Ik heb nu eindelijk het gevoel iets te hebben waarover ik kan redeneren en uitspraken kan doen (vind ik imho extreem belangrijk als je de verantwoording hebt over de techniek).
De .NET guys aan de andere kant van de muur, hebben die ook dit soort problemen?
[...]
Zie ik eruit als iemand die gek is? Een andere or mapper waar ik de laatste tijd goeie verhalen van heb gehoord is Cayenne. Schijnt stuk eenvoudiger en duidelijker te zijn dan Hibernate. Alleen stond me niet aan dat je domain objecten een bepaalde interface moeten implementeren (niemand heeft iets te zeggen over mijn domain objecten).
Fout. Jij moet pragmatischer gaan denken, denk ik. "As't net kin sa't mat, dan mat it mar sa't kin" zeggen ze in je geliefde buurprovincie, en dat zouden meer mensen moeten toepassen. Het punt is nl. dat er niet '1' goede oplossing is maar wel 1000. Je kunt wel erg rechtlijning zijn in het opzetten van je domain model, maar als dat dan tegelijkertijd onhandig werkt met je data-access tool, dan ben je IMHO onhandig bezig.
ps:
90% van onze problemen komen trouwens voort uit de sessie/open sessie in view/detached/attached/transient objecten problematiek.
Dat komt direct voort uit het gebruik van een centrale session object dat de mappings kent: een entity object los van de session heeft geen logica in zich om zich te gedragen als een persistable object. Dit hoeft dat entity object zelf ook niet te weten, maar het is wel essentieel (IMHO) wanneer je bv een graph opbouwt in je GUI, die naar beneden stuurt en daar gaat persisten na bewerking, want dan moet die graph ineens aan een sessie gehangen worden en moet alles ineens werken.

Die interface van Cayenne is precies daarvoor bedoelt. Dat jij dan dat niet wilt, tja... dat is precies waar ik op doelde: je wilt wel dolgraag van die ellende af, maar daar ook maar 1 consessie voor doen is niet aan de orde. Ik zeg dan: dan moet je het ook maar zelf uitzoeken. Immers: in hibernate, moet de session ineens change-tracking gaan uitvoeren op een object dat het wellicht nooit gezien heeft maar het object is _NIET NIEUW_. Dat weet die session dan niet. Met een change-tracking interface weet die session dat wel. Scheelt weer wat ellende :)

[ Voor 76% gewijzigd door EfBe op 29-08-2005 09:30 ]

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


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op maandag 29 augustus 2005 @ 08:53:
[...]
Dit systeem is toch niet goed; als ik bv een Customer en een object van een ander type binnen dezelfde transactie wil opslaan, dan zit ik weer met de gebakken peren.
SaveEntity(entity) en niet SaveCustomer, SaveOrder etc.

Verder lijkt het me logisch dat je meerdere SaveEntity() calls kunt doen na een start van een transaction, die gebruiken toch gewoon de active transaction? En als je recursive wilt saven, dan moet er automatisch een transaction worden aangemaakt.

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


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Scott Bellware was iig te spreken over NHibernate.
In de comments staan er trouwens een paar links naar voorbeeldapp's die gebruik maken van nhibernate, maar die moet ik zelf nog eens bekijken. Dat zal ergens voor 's avonds of in het weekend zijn.

[ Voor 45% gewijzigd door whoami op 29-08-2005 09:54 ]

https://fgheysels.github.io/


  • tijn
  • Registratie: Februari 2000
  • Laatst online: 22-03 21:36
Alarmnummer schreef op zondag 28 augustus 2005 @ 21:45:
[...]
Ach man..breek me de bek niet open. Ik en een collega (wij zijn verantwoordelijk voor de technische beslissingen) zijn er erg lang mee bezig geweest. Op het moment dat 1 ding werkt, storten 2 dingen weer in en maakt het toevoegen van een 3e nog een stuk lastiger. We zijn uiteindelijk op iets bruikbaars uitgekomen maar er zitten nog wel een paar gaten in. Ik heb nu eindelijk het gevoel iets te hebben waarover ik kan redeneren en uitspraken kan doen (vind ik imho extreem belangrijk als je de verantwoording hebt over de techniek).
EfBe schreef op maandag 29 augustus 2005 @ 09:11:

De .NET guys aan de andere kant van de muur, hebben die ook dit soort problemen?
Bij webapplicaties zijn er eigenlijk geen noemenswaardige problemen. Gewoon 1 sessie (Unit of work) per request en dat werkt lekker.
Anders wordt het bij winforms of gedistribueerde applicaties. Om lazy loading van gerelateerde objecten (lijsten, proxies) mogelijk te houden moet de sessie veel langer in leven blijven dan eigenlijk verstandig is. Er is wel omheen te werken door de sessie's kort open te houden en veel data te prefetchen, maar ja, dan zit je toch wel weer heel doelgericht stukjes van je object graph te vullen terwijl je dit nou net niet zelf wilt doen.
Wat ik verder bijzonder storend vind is dat iedereen die op bovenstaand probleem commentaar geeft op het Hibernate forum compleet afgeserveerd wordt door de makers. Ze zullen nooit toegeven dat hun bedenksel ook zwakke punten heeft. Gelukkig is men op het NHibernate forum wel aardig voor elkaar :).

Cuyahoga .NET website framework


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Haha :D ->
It's really unfortunate that a couple of really visible and really bright folks have turned so many people away from object-relational persistence in .NET by simply being such - well, bastards. It's a shame that more people haven't adopted or at least investigated the approaches, especially when some of the most important voices seem more ready to vilify and humiliate folks in public, rather than set them on the path.
Thomas! See what you've done! Everybody runs away from O/R mapping!
Treurig wel, dat meneer Bellware er niet doorheen kijkt. Ik zie nu dat hij over meerdere mensen spreekt... ach jee, wie zou hij nog meer bedoelen? ;)
In de comments staan er trouwens een paar links naar voorbeeldapp's die gebruik maken van nhibernate, maar die moet ik zelf nog eens bekijken. Dat zal ergens voor 's avonds of in het weekend zijn.
het zal mij benieuwen in hoeverre ze hibernate 3.0 features gaan inbouwen in nhibernate. hibernate 3.0 heeft een aantal interessante zaken maar om dat te porten wordt lastig denk ik.
tijn schreef op maandag 29 augustus 2005 @ 10:36:
Bij webapplicaties zijn er eigenlijk geen noemenswaardige problemen. Gewoon 1 sessie (Unit of work) per request en dat werkt lekker.
Anders wordt het bij winforms of gedistribueerde applicaties. Om lazy loading van gerelateerde objecten (lijsten, proxies) mogelijk te houden moet de sessie veel langer in leven blijven dan eigenlijk verstandig is. Er is wel omheen te werken door de sessie's kort open te houden en veel data te prefetchen, maar ja, dan zit je toch wel weer heel doelgericht stukjes van je object graph te vullen terwijl je dit nou net niet zelf wilt doen.
Wat ik verder bijzonder storend vind is dat iedereen die op bovenstaand probleem commentaar geeft op het Hibernate forum compleet afgeserveerd wordt door de makers. Ze zullen nooit toegeven dat hun bedenksel ook zwakke punten heeft. Gelukkig is men op het NHibernate forum wel aardig voor elkaar :).
Nou, ik het kader van dit session probleem kunnen ze ook moeilijk anders, want het is de basis van het gehele ontwerp. Er is ook niet echt een andere oplossing wil je toch POCO/POJO blijven ondersteunen: changetracking en persistence info moet je dan nl. buiten de objects doen / opslaan en dat levert nu eenmaal een session object op. OF je moet bytecode gaan toevoegen zoals Versant doet (die genereert een nieuwe assembly en plaatst de persistence code in de getters/setters). Dat heeft meer nadelen dan voordelen, dus lijkt me ook niet de juiste weg.

Thomas Tomiczek wordt wel afgezeken door meneer Bellware, maar veelal heeft ie wel gelijk. Hij roept bv steevast: give me an example why POCO is required. Een goed sluitend antwoord komt dan zelden (logischerwijs). Dat levert wel een interessante situatie op: sommige mensen willen PER SE POCO/POJO, maar zeuren wel over de nadelen die dat meebrengt en of die dan even opgelost kunnen worden. Dat KAN wel, maar dan heb je geen POCO/POJO meer, en wat nu zo interessant is, is dat men de REDEN waarom men per se POCO/POJO wil leidend maakt terwijl het probleem/de nadelen van POCO/POJO juist leidend zijn in het project!

[ Voor 53% gewijzigd door EfBe op 29-08-2005 11:31 ]

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


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Blijkbaar heeft Paul Wilson's OR mapper wel de mogelijkheid om lazy loading te gaan doen, zonder dat je je session moet openhouden.
klik

https://fgheysels.github.io/


  • tijn
  • Registratie: Februari 2000
  • Laatst online: 22-03 21:36
whoami schreef op maandag 29 augustus 2005 @ 11:27:
Blijkbaar heeft Paul Wilson's OR mapper wel de mogelijkheid om lazy loading te gaan doen, zonder dat je je session moet openhouden.
klik
Klopt. Hiervoor moet je wel Wilson-specifieke types gebruiken (ObjectSet en ObjectHolder) in je domain classes. Als je er geen problemen mee hebt dat die ietwat 'vervuilen' werkt het prima.

Cuyahoga .NET website framework


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op maandag 29 augustus 2005 @ 11:27:
Blijkbaar heeft Paul Wilson's OR mapper wel de mogelijkheid om lazy loading te gaan doen, zonder dat je je session moet openhouden.
klik
Ja, ik ook, het is ook niet zo moeilijk hoor :), zoals Tijn zegt heb je wel als nadeel dat je niet POCO/POJO meer kunt werken.

Mijn 'selfservicing' werkt zelfs volledig sessie-loos (en adapter gebruikt alleen een persistence service component, de entities houden alles zelf bij, dus ook in een disconnected environment (disconnected== los van wat voor sessie/adapter/context dan ook).

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


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

Alarmnummer

-= Tja =-

tijn schreef op maandag 29 augustus 2005 @ 10:36:
Bij webapplicaties zijn er eigenlijk geen noemenswaardige problemen. Gewoon 1 sessie (Unit of work) per request en dat werkt lekker.
Het ligt aan je manier van werken. Op het moment dat je geen detached objecten hebt zijn de problemen minder groot. Maar op het moment dat je daar mee te maken krijgt (krijg je als je werkt met statefull pagebased systemen) dan komen de problemen. Systemen zoals Tapestry, Wicket en hetgeen wat we nu gebruiken hebben allemaal last van deze problemen.

Je kunt dus niet zeggen dat het allemaal zo eenvoudig werkt.

We hebben intussen wel een werkbare (en eenvoudige) oplossing (mede dankzij mensen op het Spring forum). Maar het heeft een lange tijd geduurd voordat we zover waren. En verder heb ik nog 1001 vragen waarbij ik me echt afvraag: hoe moet ik in godsnaam dit beantwoord krijgen als de tijd zover is.

[edit]
nog een leuk hibernate gevalletje:

code:
1
2
3
4
5
6
Sessie s = sessieFactory.create();
s.save(new Persoon("jan"));
Transactie t = s.startTransactie();
s.save(new Persoon("kees"));
t.commit();
s.close();


Hoeveel objecten zijn er nu in de db gekomen? 1 of 2? :)

[ Voor 42% gewijzigd door Alarmnummer op 29-08-2005 12:05 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
^^
Normaal gezien zouden het er 2 moeten zijn, maar je zou het niet vragen als het antwoord 1 was.

https://fgheysels.github.io/


  • tijn
  • Registratie: Februari 2000
  • Laatst online: 22-03 21:36
Alarmnummer schreef op maandag 29 augustus 2005 @ 11:55:
[...]

Het ligt aan je manier van werken. Op het moment dat je geen detached objecten hebt zijn de problemen minder groot. Maar op het moment dat je daar mee te maken krijgt (krijg je als je werkt met statefull pagebased systemen) dan komen de problemen. Systemen zoals Tapestry, Wicket en hetgeen wat we nu gebruiken hebben allemaal last van deze problemen.
Op zich kun je met ISession.lock() toch heel aardig objecten re-attachen? Hangt wel een beetje van je cascade settings af of ook meteen je hele graph weer opgenomen wordt in de sessie.
nog een leuk hibernate gevalletje:

code:
1
2
3
4
5
6
Sessie s = sessieFactory.create();
s.save(new Persoon("jan"));
Transactie t = s.startTransactie();
s.save(new Persoon("kees"));
t.commit();
s.close();


Hoeveel objecten zijn er nu in de db gekomen? 1 of 2? :)
Hangt van je flushmode af :).

Cuyahoga .NET website framework


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

Alarmnummer

-= Tja =-

tijn schreef op maandag 29 augustus 2005 @ 14:08:
Op zich kun je met ISession.lock() toch heel aardig objecten re-attachen?
Yep. Maar is wel iets waar je rekening moet houden. Op het moment dat je een 'statefull' java-pagina hebt die tussen meerdere request wordt gebruikt dan moet je wel de ruimte bieden (of aangeboden krijgen) om te kunnen attachen.

Je moet altijd proberen om objecten weer te reatachen aan een sessie anders kan het voorkomen dat je van 1 entiteit meerdere instanties in het geheugen krijgt. En moet je er rekening mee houden dat alle wijzigingen op attached objecten (zonder dat je daar nog een save op aan hoeft te roepen) gepersist worden in de db. Dit kan ook voor vreemde problemen zorgen en het is lastig om in een algemeen model te plaatsen.

Bij het bedrijf waar ik werk zijn ik en een collega verantwoordelijk voor de techniek. We willen dat andere mensen zich zo weinig mogelijk van allerlei hibernate problematiek hoeven aan te trekken en dat ze er wel komen als ze bepaalde guidelines volgen. het probleem zit hem in het opstellen van goeie, heldere en simpele guidelines (en eventueel wat handige implementaties). Ik kan voor iedere situatie wel weer iets bedenken maar dit willen we verhinderen zodat we sneller kunnen produceren en code hebben van een vergelijkbare kwaliteit en structuur (maakt onderhoud ook veel eenvoudiger). Dit is noodzaak als je relatief eenvoudige webapplicaties in elkaar moet zetten en geen verlies wilt maken. En het is ook nodig om andere developers te helpen als er iets fout gaat.
Hangt van je flushmode af :).
Yep. Maar je zit wel ff achter je oren te krabben als je het voor het voor de kiezen krijgt en je flushmode niet goed hebt staan.

Ik moet ook eerlijk toegeven dat ik nog steeds niet alles 100% begrijp en zeker niet 100% kan verwoorden. Maar persoonlijk vind ik niet dat dit mij aangerekend kan worden. Ik zit regelmatig achter vrij complexe stuff (veel concurrency zaken, zoek problemen, prolog compilers etc). De materie is complex, maar uitzoekbaar. Bij Hibernate voel ik me verloren en dat is gewoon te wijten aan de kwaliteit van het product en het soort mensen. Hoe meer ik er eigelijk over vertel hoe meer ik het eigelijk een waanzinnig zuig product vind.

[ Voor 24% gewijzigd door Alarmnummer op 29-08-2005 15:06 ]

Pagina: 1