[OO] Database ID's vs. references naar classes

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • BikkelZ
  • Registratie: Januari 2000
  • Laatst online: 21-02 08:50
Ik loop al een tijdje tegen het volgende probleem aan, waarbij theorie en praktijk elkaar een beetje bijten naar mijn idee. Als ik het helemaal schoolvoorbeeld OO zou moeten doen dan zou iedere class netjes refereren naar andere classes die daarmee geassocieerd zijn. Bijvoorbeeld een Klant zou dan een Lijst met Orders hebben, en iedere keer als ik die Lijst met Orders vraag aan de Klant dan zou die gevuld moeten zijn, want een Klant bestaat nu eenmaal uit o.a. de eigenschap Lijst met Orders, ook al is die leeg, dan heeft die Klant gewoon geen Orders.

Ga je dat in een database opslaan voor een website heb je verassingsgewijs dan een tabel Klant en een tabel Order, waar iedere Order een KlantId heeft. Maaarrrr nu komt het vaker voor dat om diverse technische (circular references bijvoorbeeld) of performance technische (waarom alle orders met orderregels etc ophalen als je alleen de naam wilt weten?) redenen dat dus die 'zekerheid' die je hebt, namelijk dat je altijd op die manier de actuele Lijst met Orders hebt, niet meer bestaat. Tenslotte zou ik een simpele fetch gedaan kunnen hebben waarbij ik wel de simpele members van Klant heb maar niet meer de Lijst met Orders vul, waardoor het lijkt alsof deze klant geen Orders meer heeft terwijl ik ze alleen maar niet heb opgehaald.

Dit lijkt mij echt een enorme bron van mogelijke NP exceptions, foutieve waardes en andere zaken die veel geld kosten om op te lossen en nog jaren later in de vorm van bugs terug blijven komen. Hoe zorg ik er voor dat mijn datamodel weer net zo betrouwbaar wordt alsof ik het alleen maar in mijn geheugen zou hebben? Moet ik dan gewoon die references afschaffen en in die classes integers met foreign keys opslaan en die pas resolven als ik ze nodig heb? Maar waarom doe ik dan nog OO?

[ Voor 7% gewijzigd door BikkelZ op 07-11-2008 13:24 ]

iOS developer


Acties:
  • 0 Henk 'm!

  • Stoffel
  • Registratie: Mei 2001
  • Laatst online: 08:38

Stoffel

Engineering the impossible

Of je gebruikt een ORM (zoals bijvoorbeeld Nhibernate) die je objecten ophaalt wanneer ze nodig zijn. Dan is (in jouw voorbeeld) het bekend dat er een lijst met orders is, maar tot het moment dat je een order echt nodig hebt zit die niet daadwerkelijk in het geheugen.

Acties:
  • 0 Henk 'm!

  • BikkelZ
  • Registratie: Januari 2000
  • Laatst online: 21-02 08:50
Tja aan de ene kant betekent ORM natuurlijk vaak wel performanceverlies, aan de andere kant zijn alle maatregelen die je neemt om het probleem op te lossen natuurlijk ook een soort ORM.

Stel dat je een boolean OrderLijstIsGevuld hebt die op true gezet wordt als die Lijst gevuld is, en dat als die op false staat en de Lijst met Orders geraadpleegd wordt er een exception gethrowd wordt, maak ik het me zelf dan alleen maar moeilijk of heeft dat in de praktijk wel degelijk voordelen bij debuggen/unit tests etcetera?

Maar is iedere representatie van data uit een database in een object niet na 0.0000000001 seconde al meteen onbetrouwbaar omdat die rij inmiddels gewijzigd kan zijn?

[ Voor 13% gewijzigd door BikkelZ op 07-11-2008 13:38 ]

iOS developer


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:57
BikkelZ schreef op vrijdag 07 november 2008 @ 13:37:
Tja aan de ene kant betekent ORM natuurlijk vaak wel performanceverlies, aan de andere kant zijn alle maatregelen die je neemt om het probleem op te lossen natuurlijk ook een soort ORM.
Waarom betekent ORM vaak wel performance-verlies ?
Met de meeste OR/M mappers heb je best wel een en ander in de hand.

Als je bv een overzicht/lijst van objecten wilt gaan tonen, dan kan je er bv ook voor kiezen dat je een 'lightweight' view object maakt, die enkel de gegevens bevat die jij nodig hebt. De mapper zal er dan wel voor zorgen dat enkel de nodige info uit de DB gehaald wordt, zodanig dat het object (lijst van objecten) kan opgevuld worden.
Stel dat je een boolean OrderLijstIsGevuld hebt die op true gezet wordt als die Lijst gevuld is, en dat als die op false staat en de Lijst met Orders geraadpleegd wordt er een exception gethrowd wordt, maak ik het me zelf dan alleen maar moeilijk of heeft dat in de praktijk wel degelijk voordelen bij debuggen/unit tests etcetera?
Als je een OR/M mapper als (N)Hibernate gebruikt, dan moet je helemaal geen boolean flag gaan bijhouden waarmee je zegt of een lijst wel of niet gevuld is.
Als je Lazy Loading gaat gaan gebruiken binnen NHibernate, wordt dat allemaal netjes voor jou geregeld.
Wil je geen OR/M mapper gaan gebruiken, maar wel gebruik willen maken van LazyLoading, dan kan je natuurlijk nog altijd zelf een lazy-loading collection gaan implementeren.
Maar is iedere representatie van data uit een database in een object niet na 0.0000000001 seconde al meteen onbetrouwbaar omdat die rij inmiddels gewijzigd kan zijn?
Tja ... Dat risico heb je toch ook als je niet met objecten gaat gaan werken ? Jij haalt data op uit een DB, je plaatst die data in een object / dataset / whatever ... Tegen de tijd dat jij die data gaat gaan bewerken / saven, kan er idd weer iemand anders die gegevens aangepast hebben. Hier kan je gebruik gaan maken van optimistic locking bv.
Als je niet wil dat 2 (of meer) personen tegelijk een bepaald record gaan bekijken, dan kan je gebruik maken van pessimistic locking, maar of dat dat wenselijk is ...

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Verwijderd

Al aan een dergelijke oplossing gedacht?

C#:
1
2
3
4
5
6
7
8
9
10
private List<Orders> _orders = null;
public List<Orders> Orders
{
    get 
    {
        if (_orders== null) Orders = OrderManager.GetList(this);
        return _orders; 
    }
    set { _orders= value; }
}


Bovenstaande code kun je opnemen in de class 'Klant'. Je kunt op deze manier altijd Klant.Orders opvragen.
Standaard worden de orders niet ingelezen, pas bij het opvragen worden ze geladen uit de database.

[ Voor 27% gewijzigd door Verwijderd op 07-11-2008 16:10 ]


Acties:
  • 0 Henk 'm!

  • Stoffel
  • Registratie: Mei 2001
  • Laatst online: 08:38

Stoffel

Engineering the impossible

Verwijderd schreef op vrijdag 07 november 2008 @ 16:09:
Al aan een dergelijke oplossing gedacht?

C#:
1
2
3
4
5
6
7
8
9
10
private List<Orders> _orders = null;
public List<Orders> Orders
{
    get 
    {
        if (_orders== null) Orders = OrderManager.GetList(this);
        return _orders; 
    }
    set { _orders= value; }
}


Bovenstaande code kun je opnemen in de class 'Klant'. Je kunt op deze manier altijd Klant.Orders opvragen.
Standaard worden de orders niet ingelezen, pas bij het opvragen worden ze geladen uit de database.
Mja, maar in de lifetime van dat object mag er dus niets wijzigen in de database, want die wijziging zul je dan niet terugzien in de applicatie. Dat is iets waar de meeste ORM's wel rekening mee houden.

Acties:
  • 0 Henk 'm!

Verwijderd

Stoffel schreef op vrijdag 07 november 2008 @ 16:24:
[...]


Mja, maar in de lifetime van dat object mag er dus niets wijzigen in de database, want die wijziging zul je dan niet terugzien in de applicatie. Dat is iets waar de meeste ORM's wel rekening mee houden.
Dan zou dat toch voor ieder gegeven van een klant gelden; de naam kan ook worden aangepast.

Bovendien kun je natuurlijk net zo makkelijk *altijd* de order ophalen en niet alleen wanneer de list null is.

[ Voor 9% gewijzigd door Verwijderd op 07-11-2008 16:28 ]


Acties:
  • 0 Henk 'm!

  • BikkelZ
  • Registratie: Januari 2000
  • Laatst online: 21-02 08:50
Verwijderd schreef op vrijdag 07 november 2008 @ 16:09:
Al aan een dergelijke oplossing gedacht?

C#:
1
2
3
4
5
6
7
8
9
10
private List<Orders> _orders = null;
public List<Orders> Orders
{
    get 
    {
        if (_orders== null) Orders = OrderManager.GetList(this);
        return _orders; 
    }
    set { _orders= value; }
}


Bovenstaande code kun je opnemen in de class 'Klant'. Je kunt op deze manier altijd Klant.Orders opvragen.
Standaard worden de orders niet ingelezen, pas bij het opvragen worden ze geladen uit de database.
Ben ik inderdaad ook mee aan het stoeien geweest, maar is niet altijd even makkelijk ivm circular references. Want stel dat OrderManager ook al naar Klant refereert. En inderdaad kan de data verouderd zijn, maar daarvoor hoef je natuurlijk alleen maar de private member weg te laten. Nadeel is dat set dan weer niet zo handig werkt.

Maar ik merk eigenlijk dat ik de keuze heb tussen ORM en doorgaan zoals ik nu al werk?

iOS developer


Acties:
  • 0 Henk 'm!

  • FireDrunk
  • Registratie: November 2002
  • Laatst online: 17:56
Je kunt ook een veld in de database opnemen met een boolean die word geset op het moment dat je een rij aan het editen bent.

Krijg hele simpele vorm van locking in je database.

Even niets...

Pagina: 1