[OOP]Create,Insert,Delete methoden waar te plaatsen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Razr
  • Registratie: September 2005
  • Niet online
Ik ga me best doen om mijn vraagstuk zo duidelijk mogelijk te omschrijven.

Waar loop ik tegenaan?:
Stel ik heb een klasse maken Gebruiker. Deze zou er als volgt uit kunnen zien (simpel vb):
C#:
1
2
3
4
5
6
public class Gebruiker 
{
    public int GebruikerId { get; private set; }
    public string Naam { get; private set; }
    //etc.
}


Nu stelt deze klasse dus een gebruiker voor waarvan de gegevens zijn opgeslagen in de database. Verder wil ik ook 'dingen' met deze gegevens kunnen doen (daar heb ik ook methoden voor gemaakt in de klasse Gebruiker).

Mijn vraag is: "Hoe moet ik volgens de OOP principes een object laden met gegevens. Waar moet ik die methoden definieren? Hetzelfde geldt voor het opslaan van de gegevens in de db van een nieuw gevuld object."

Nu maak ik een klasse gebruiker bijv. zo:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
public class Gebruiker 
{
    public void LaadGebruiker(int id)
    {
        //Hier wordt bijv uit een db gegevens opgehaald
    }
    public void SlaGebruikerOp(string naam, string wachtwoord)
    {
        //Hier worden de parameters gecontroleerd
        //en opgeslagen in de db.
    }
}


Maar dan moet ik ook methoden gaan aanmaken voor een nieuwe gebruiker, of het verwijderen van een gebruiker. Het lijkt me niet dat dit de bedoeling is om dat ook allemaal in de klasse Gebruiker te stoppen? Vooral om je ook met de velden zit die leeg zijn bij het initialiseren. Het is lastig uit te leggen maar ik heb het gevoel dat bijv. bij de Gebruiker klasse het aanmaken van een gebruiker niet in de klasse zelf hoort.

Het enige wat ik dan kan bedenken is een soort beheer klasse die alle gebruikers laad uit de db en vervolgens een lijst van Gebruiker objecten terug geeft. Ook zou deze klasse een NieuweGebruiker() methode kunnen bevatten. Hiermee kun je dan de veld waarden als parameter meegeven?

Bovenstaande betekend dan wel weer dat je voor elke klasse welke geladen, opgeslagen kan worden een 'beheer' klasse moet schrijven. Stel je voor dat je klassen hebt als Foto, Album, Gebruiker, Rol, Reactie etc. Dan kan dit ook best voor een onduidelijke structuur gaan zorgen.

Graag hoor ik van jullie wat dé manier is hiervoor! :)

Acties:
  • 0 Henk 'm!

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 12-09 07:46

Kettrick

Rantmeister!

Die beheer klasse noemt men ook wel een DAO ( Data Access Object ), google daar voor de grap eens op :)

Acties:
  • 0 Henk 'm!

  • Razr
  • Registratie: September 2005
  • Niet online
RoeLz schreef op woensdag 10 december 2008 @ 19:37:
Die beheer klasse noemt men ook wel een DAO ( Data Access Object ), google daar voor de grap eens op :)
Dit is inderdaad wat ik bedoelde. Ik heb even wat materiaal doorgelezen en modellen bekeken. Het is volgens mij precies als ik in mijn openings post beschreef. Je moet voor elke klassen een DAO variant maken welke het ophalen/wegschrijven/updaten/verwijderen gaat regelen.

Dan heb ik nog een vraagje over het 'vullen' van het object in de DAO klasse. Bij sommige velden gebruik ik nu private set's. Dit omdat ze read-only zijn (bijv. een ID kan niet veranderd worden). Maar ik zal alles wel veranderbaar moeten maken anders kan een DAO dit veld nooit gevuld krijgen?

Acties:
  • 0 Henk 'm!

  • _Erikje_
  • Registratie: Januari 2005
  • Laatst online: 10-09 20:55

_Erikje_

Tweaker in Spanje

DAO's zijn zo 2007 :P Misschien kan je beter kijken naar object relational mapping(ORM).Dan zit die functionaliteit gewoon in je domein object ipv een aparte klasse (minder code, cleanere code)

Acties:
  • 0 Henk 'm!

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 12-09 07:46

Kettrick

Rantmeister!

_Erikje_ schreef op woensdag 10 december 2008 @ 20:12:
DAO's zijn zo 2007 :P Misschien kan je beter kijken naar object relational mapping(ORM).Dan zit die functionaliteit gewoon in je domein object ipv een aparte klasse (minder code, cleanere code)
een ORM kan je ook prima gebruiken in combinatie met DAO's, ik doe zelfs niets anders :). Je DAO's bevatten dan geen SQL maar ORM code, leuk voorbeeld wat ik zelf nog steeds vrijwel onaangepast gebruik : http://www.hibernate.org/328.html

Acties:
  • 0 Henk 'm!

  • _Erikje_
  • Registratie: Januari 2005
  • Laatst online: 10-09 20:55

_Erikje_

Tweaker in Spanje

RoeLz schreef op woensdag 10 december 2008 @ 20:16:
[...]


een ORM kan je ook prima gebruiken in combinatie met DAO's, ik doe zelfs niets anders :). Je DAO's bevatten dan geen SQL maar ORM code, leuk voorbeeld wat ik zelf nog steeds vrijwel onaangepast gebruik : http://www.hibernate.org/328.html
Ik doelde een beetje op de manier hoe een framework als RubyOnRails (of Grails) omgaat met ORM. In elk domein object zit standaard de CRUD functionaliteit. Geen flauw idee of dit er ook voor C# is...

(die eerste zijn was wel een beetje een flame, leuk dat je hapt >:) )

Acties:
  • 0 Henk 'm!

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 12-09 07:46

Kettrick

Rantmeister!

_Erikje_ schreef op woensdag 10 december 2008 @ 20:21:
[...]


Ik doelde een beetje op de manier hoe een framework als RubyOnRails (of Grails) omgaat met ORM. In elk domein object zit standaard de CRUD functionaliteit. Geen flauw idee of dit er ook voor C# is...
Niet iedereen is daar gelukkig mee, loopt toevallig ook een draadje over -> Utility methods in Entity of niet?

Zal vast omheen te hacken zijn, maar niet iedereen is blij met prefab spul :)
(die eerste zijn was wel een beetje een flame, leuk dat je hapt >:) )
offtopic:
als ik hap staat er wel :( :X :| :/ ;( : :r etc ;)

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
_Erikje_ schreef op woensdag 10 december 2008 @ 20:21:
[...]


Ik doelde een beetje op de manier hoe een framework als RubyOnRails (of Grails) omgaat met ORM. In elk domein object zit standaard de CRUD functionaliteit. Geen flauw idee of dit er ook voor C# is...

(die eerste zijn was wel een beetje een flame, leuk dat je hapt >:) )
Jawel, Castle ActiveRecord is zo'n 'ActiveRecord' framework dat eigenlijk gebruik maakt van NHibernate;
Zelf ben ik zo geen voorstander om die CRUD functionaliteit in m'n domain entities te plaatsen, en dus maak ik gebruik van repository classes waarmee ik dus entities (aggregate roots eigenlijk) kan saven, updaten, verwijderen, etc ...
RoeLz
Zal vast omheen te hacken zijn, maar niet iedereen is blij met prefab spul
Daar is, in Castle ActiveRecord idd omheen te hacken.
Je kan perfect gebruik maken van dat ActiveRecord framework, zonder dat je je entities moet 'vervuilen' met CRUD functionaliteit.
Razr:
Je moet voor elke klassen een DAO variant maken welke het ophalen/wegschrijven/updaten/verwijderen gaat regelen.
't Is te zien wat je DAO eigenlijk precies doet ...
Je zou per 'tabel' een DAO kunnen maken, die SQL statements uitvoert op die tabel.
Dan kan je daarnaast een repository hebben, die verschillende DAO's aanspreekt; per 'aggregate root' heb je dan een repository.
Die repository spreek je vanuit je client-code aan (UI of service layer ... ); enkel de repository praat met de DAO's.

Echter, als je gebruik gaat gaan maken van een O/R mapper, heb je die DAO's eigenlijk niet meer nodig. Je repository gebruikt dan de O/R mapper.
Razr
Bij sommige velden gebruik ik nu private set's. Dit omdat ze read-only zijn (bijv. een ID kan niet veranderd worden).
Maar ik zal alles wel veranderbaar moeten maken anders kan een DAO dit veld nooit gevuld krijgen?
Reflection. :)
Maar, again, een O/R mapper lost dat voor jou wel op.
Mijn vraag is: "Hoe moet ik volgens de OOP principes een object laden met gegevens. Waar moet ik die methoden definieren? Hetzelfde geldt voor het opslaan van de gegevens in de db van een nieuw gevuld object."
Hoe ga je (efficient) een lijst van entities gaan ophalen als je geen O/R mapper gebruikt ?
Het kan wel, maar het is toch wel even wat plumbing.
Graag hoor ik van jullie wat dé manier is hiervoor!
There's no such thing as a silver bullet. :)

Even verschillende mensen door elkaar gequoted

[ Voor 57% gewijzigd door whoami op 10-12-2008 23:25 ]

https://fgheysels.github.io/


  • Razr
  • Registratie: September 2005
  • Niet online
Ik ben nu inderdaad bezig geweest met een ORM (CoolStorage.NET in dit geval) en dit werkt heel mooi. Het enige wat ik niet wil is dat de programmacode (de niet data layer) de ORM librairies moet importeren. Dit is nu wel het geval omdat de door de ORM 'gevulde' objecten erven van een supertype.

Als ik het goed begrijp is hier een repository voor? Deze fungeert als het ware tussen je ORM en je overige programma code? Je zou in een repository een methode kunnen maken die bijv. al je gebruikers ophaalt, de repository regelt dit vervolgens met de ORM en geeft daarna een lijst terug.
Dan komt gelijk een nieuwe vraag naar boven 'Dan moet ik nieuwe klassen maken welke in een lijst geretourneerd kunnen worden'? Want ik kan vanuit de repository geen (bijv. Gebruiker) objecten retourneren welke ook gebruikt worden door het ORM want dan moet ik alsnog overal zijn librairies importeren. Dan moet ik dus dubbelop klassen maken? Zowel een voor de repository die deze kan retourneren, en een voor het ORM omdat deze de velden moet kennen/vullen?

Het zou ook kunnen dat ik er helemaal naast zit ;) Ik heb zeker gegoogled op dingen als repository c#, en heb hier het boek Design Patterns maar hier vind ik niet veel terug over repository's. Volgens wikipedia houdt het in 'a place where data are stored' vandaar dat ik gok dat het een laag betreft tussen je ORM en programma.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Razr schreef op donderdag 11 december 2008 @ 12:08:
Ik ben nu inderdaad bezig geweest met een ORM (CoolStorage.NET in dit geval) en dit werkt heel mooi. Het enige wat ik niet wil is dat de programmacode (de niet data layer) de ORM librairies moet importeren. Dit is nu wel het geval omdat de door de ORM 'gevulde' objecten erven van een supertype.

Als ik het goed begrijp is hier een repository voor?
Wat jij wilt is een POCO gebaseerde o/r mapper (een o/r mapper die jouw classes can saven/laden van de database).

echter, je hebt altijd code in jouw project die daar puur zit omdat je o/r mapper XYZ gebruikt. Bv virtual methods/properties, ctor zonder parameters, etc.

Dat jij niet wilt dat de rest van het project de o/r mapper assembly niet referenced, waar is dat op gebaseerd? Je gevoel? Want er is niet echt een rationele reden voor (en voordat je denkt: jawel, die is er wel: bel je MS ook op of ze alle code die jij niet gebruikt in mscorlib.dll willen plaatsen in een aparte dll zodat jij die dll niet hoeft de referencen?)

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


  • Razr
  • Registratie: September 2005
  • Niet online
EfBe schreef op donderdag 11 december 2008 @ 13:05:
[...]

Wat jij wilt is een POCO gebaseerde o/r mapper (een o/r mapper die jouw classes can saven/laden van de database).

echter, je hebt altijd code in jouw project die daar puur zit omdat je o/r mapper XYZ gebruikt. Bv virtual methods/properties, ctor zonder parameters, etc.

Dat jij niet wilt dat de rest van het project de o/r mapper assembly niet referenced, waar is dat op gebaseerd? Je gevoel? Want er is niet echt een rationele reden voor (en voordat je denkt: jawel, die is er wel: bel je MS ook op of ze alle code die jij niet gebruikt in mscorlib.dll willen plaatsen in een aparte dll zodat jij die dll niet hoeft de referencen?)
Het gevoel ontstaat omdat ik op dit moment bezig ben met een Class Library project. Hierin gebruik ik dus een ORM. Wanneer ik straks met dit project x klaar ben en de .dll aan een andere ontwikkelaar geef dan zal hij in dit geval ook in zijn code naar mijn gebruikte ORM moeten refereren dit wil ik juist voorkomen.
Tuurlijk is het onoverkoombaar dat de .dll van de ORM aanwezig moet zijn als reference voor de .dll van project x. Dit is ook geen probleem. Maar stel dat de ontwikkelaar van project abc helemaal geen kaas heeft gegeten van een ORM mapper en die wil mijn .dll van project x gebruiken? Wanneer hij dan objecten wil opvragen of benaderen zal hij dit toch met methoden moeten doen van de O/R mapper. Hierdoor krijg ik het gevoel dat ik nog een laag mis?

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
Razr schreef op donderdag 11 december 2008 @ 13:31:
[...]

Het gevoel ontstaat omdat ik op dit moment bezig ben met een Class Library project. Hierin gebruik ik dus een ORM. Wanneer ik straks met dit project x klaar ben en de .dll aan een andere ontwikkelaar geef dan zal hij in dit geval ook in zijn code naar mijn gebruikte ORM moeten refereren dit wil ik juist voorkomen.
Hoe gaat die andere ontwikkelaar dan instanties van jouw classes kunnen persisten :?

Ik snap eigenlijk het probleem niet goed; om even bij het voorbeeld van EfBe te blijven: vind je het dan ook een probleem dat die andere ontwikkelaar het .NET framework moet installeren ?
Tuurlijk is het onoverkoombaar dat de .dll van de ORM aanwezig moet zijn als reference voor de .dll van project x. Dit is ook geen probleem. Maar stel dat de ontwikkelaar van project abc helemaal geen kaas heeft gegeten van een ORM mapper en die wil mijn .dll van project x gebruiken?
Ik denk wel dat je moet kunnen stellen dat een ontwikkelaar toch wel de skills heeft om nieuwe dingen bij te leren, en de kaas te kunnen eten ...
Wanneer hij dan objecten wil opvragen of benaderen zal hij dit toch met methoden moeten doen van de O/R mapper. Hierdoor krijg ik het gevoel dat ik nog een laag mis?
De repository zorgt voor abstractie. Deze verbergt de 'interne werking' van je O/R mapper, en zorgt voor duidelijk afgelijnde functionaliteit, zodanig dat dit meer duiding kan geven aan het domein-model. (Bv, GetGoldCustomers ).
Het is echter fout om te stellen dat je daarom niet meer op de hoogte moet zijn van de O/R mapper die er gebruikt wordt. Als je die repository gebruikt bv, zal je misschien wel een bepaald object in die repository moeten injecteren, zodanig dat deze kan werken. (Dat bepaald object kan dan, in het geval je bv NHibernate gebruikt, een ISession zijn).

Zelfs als je met POCO's aan de slag gaat, en dan bv NHibernate als O/R mapper gebruikt, zal de gebruiker (ontwikkelaar) van je domain classes met NHibernate moeten werken, want, als die gebruiker bv een service-layer schrijft die jouw classes gebruiken, dan is het die service layer die het sessie management / transaction management moet beheren, en dus moet hij op de hoogte zijn van je O/R mapper en 'm gebruiken.

Ik snap niet waarom iedereen de gebruikte infrastructuur altijd zo angstvallig wil wegstoppen ? Het is -imho- een utopie om te denken dat je een applicatie kunt bouwen, die gebruik maakt van bv een assembly waarin domain objecten gedefinieerd zijn (en door iemand anders geschreven), zonder dat je 'op de hoogte' moet zijn van de infrastructuur (zoals bv welke O/R mapper er gebruikt wordt).

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Ik vraag me af of ik het probleem verkeerd begrijp, maar wil je hier niet dat je LaadGebruiker functie gewoon static is? Zodat je kan zeggen Gebruiker.LaadGebruiker(10) wat vervolgens een instantie van Gebruiker terug geeft. Lijkt me een stuk makkelijker.

Van save zou ik gewoon een instantie-functie maken terwijl delete zowel static als niet-static kan.

Acties:
  • 0 Henk 'm!

Verwijderd

Data-base schreef op dinsdag 16 december 2008 @ 23:28:
Ik vraag me af of ik het probleem verkeerd begrijp, maar wil je hier niet dat je LaadGebruiker functie gewoon static is? Zodat je kan zeggen Gebruiker.LaadGebruiker(10) wat vervolgens een instantie van Gebruiker terug geeft. Lijkt me een stuk makkelijker.

Van save zou ik gewoon een instantie-functie maken terwijl delete zowel static als niet-static kan.
Dat kan, maar dan 'vervuil' je je domein met taken die er imho niet in thuishoren. Om een klassiek voorbeeld te nemen: een boek moet alleen een boek zijn. De logica om boeken in een bibliotheek op te slaan zit niet in de boeken zelf maar in een ander object. En dan kan je natuurlijk ook nog zaken aanhalen zoals aanpasbaarheid, veranderende implementatie, testing... Of serializen van je objecten om ze te versturen via webservices naar een client waar de database-logica niet meer relevant is. Voor mij voldoende redenen om DAO's/Repositories/... te gebruiken voor CRUDwerk.

Kom ik zelf nog eens met een vraag: stel je een DAO rechtstreeks bloot aan de UI-laag of wrap je alles in een service? De meeste methodes zullen rechtstreeks een DAO-methode aanroepen (zoals GetBoekenVanAuteur) en dus overbodig zijn, maar meer ingewikkelde methodes met meerdere DAO-aanroepen (zoals DoUitleningVanBoeken) hebben dit soort services wel nodig natuurlijk...

Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op woensdag 17 december 2008 @ 14:27:
[...]


Dat kan, maar dan 'vervuil' je je domein met taken die er imho niet in thuishoren. Om een klassiek voorbeeld te nemen: een boek moet alleen een boek zijn. De logica om boeken in een bibliotheek op te slaan zit niet in de boeken zelf maar in een ander object. En dan kan je natuurlijk ook nog zaken aanhalen zoals aanpasbaarheid, veranderende implementatie, testing... Of serializen van je objecten om ze te versturen via webservices naar een client waar de database-logica niet meer relevant is. Voor mij voldoende redenen om DAO's/Repositories/... te gebruiken voor CRUDwerk.
Maar, dat geeft de vraag: als iets anders de persistence moet verzorgen, hoe komt die dan bij de data die IN het entity object zit? Die kan daar helemaal niet bij, althans dat zou niet mogen, immers, OO, encapsulation etc.

De gehele misere komt voort uit het feit dat men het entity object gelijk ziet aan de entity instance. Maar dat is niet zo. Een entity instance is de data. De entity class instance is de bak waar een in-memory copy wordt geplaatst van de echte instance van de entity in de persistent storage (bv. database).

Het 'saven' van een entity is dus eigenlijk niets anders dan de in-memory copy syncen met de echte instance.

In dat licht zie ik niet in waarom de container van de entity instance nu zo nodig NIET de taak mag hebben de entity te persisten. Let wel: jouw voorbeeld van het boek gaat op voor de entity instance, maar dat is de data IN de entity class instance.

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


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
EfBe schreef op woensdag 17 december 2008 @ 20:41:
[...]

Maar, dat geeft de vraag: als iets anders de persistence moet verzorgen, hoe komt die dan bij de data die IN het entity object zit? Die kan daar helemaal niet bij, althans dat zou niet mogen, immers, OO, encapsulation etc.
Als je het puristisch wilt bekijken, dan kan die er inderdaad niet echt bij.
Echter, je kan je ook de vraag stellen:
Op het moment dat je entity door je 'persistence layer' geconstrueerd / populated wordt, is het dan al een entity. :P

Ik heb er eigenlijk helemaal geen probleem mee dat je persistence layer / O/R tool / whatever, mbhv reflection je entity van de nodige data voorziet.
Zowiezo is het beter dat die O/R tool of persistence layer de velden/fields/attributes (hoe je het ook wilt noemen) rechtstreeks benaderd, en niet via de eventuele properties die 'rond die fields' zitten, benaderd.
Op die manier voorkom je namelijk dat eventuele (business) logica die in de property vervat zit, uitgevoerd wordt.

Wat je natuurlijk ook altijd kunt doen, is een method 'InitializeFromDataSource( args )' maken, die je entity van alle nodige data voorziet. :)
De gehele misere komt voort uit het feit dat men het entity object gelijk ziet aan de entity instance. Maar dat is niet zo. Een entity instance is de data. De entity class instance is de bak waar een in-memory copy wordt geplaatst van de echte instance van de entity in de persistent storage (bv. database).

Het 'saven' van een entity is dus eigenlijk niets anders dan de in-memory copy syncen met de echte instance.
Voor jou is een 'transient entity' dus geen echte entity ?

https://fgheysels.github.io/

Pagina: 1