webForumDet fria alternativet

ORMapper och objektbaseratfrågor

9 svar · 575 visningar · startad av Nickemannen

NickemannenMedlem sedan aug. 20003 575 inlägg
#1

Jo jag sitter och funderar lite över hur man skall göra med objekt med många-till-många relationer.

Rent objektbaserat så tycker jag att det borde se ut såhär ungefär.

Exemplet kanske inte är jättebra men det förklarar ju iallfall många till många relationen. Säg att jag har en Kund som kan ha noll eller flera telefonnummer, samt ett telefonnnummer kan ha 0 eller flera Kunder.

PhoneNumberCollection och CustomerCollection är en klass som kan lägga till, ta bort PhoneNumber, Customer osv, ja ni fattar ungefär som i en DataRowCollection.

Exempelkoden är i C#
Klassen Customer, självklart finns det CustomerId, Name osv men för enkelhetens skulle har jag lämnat det utanför.

public Class Customer
{
private PhoneNumberCollection _phoneNumberCollection;

public PhoneNumberCollection PhoneNumbers
{
get { return this._phoneNumberCollection }
}
}

Klassen PhoneNumber ser ungefär likadan ut självklart finns det en Property för telefonnummer och Id om man så vill.

public Class PhoneNumber
{
private CustomerCollection _customerCollection;

public customerCollection customers
{
get { return this._customerCollection }
}
}

Fråga 1:
I databasen så är ju detta 3 entiteter(tabeller) En Customer, PhoneNumber, CustomerPhoneNumberIndex eftersom det är en många till många men att ha 3 objekttyper av denna går väl lite emot objektbaserattänkandet eller?

Fråga 2:
Hur skall detta läsas in?
Skall det när jag laddar in Customer också ladda in alla PhoneNumbers? Då kommer ju PhoneNumbers i sin tur ladda in alla Customers. Jag har tänkt på flera lösningar på detta problemet men alla lösningar blir tämligen komplexa och onödigt stora, någon som har någon superbra lösning på detta?

Fråga 3: Väljer man att ladda in först Customer och låter den skapa alla PhoneNumbers och lägger in i Customer och sedan hämtar PhoneNumbers igen från databasen och kör: xxxxCollection.Contains(xxx obj); t.ex. då kommer den inte att matcha även om den respresenterar exakt samma rad i databasen?

LaspMedlem sedan juli 200012 980 inlägg
#2

Ett telefon nummer har alltid ytterligare en begränsning, det gäller from - tom, för en viss kund.

NickemannenMedlem sedan aug. 20003 575 inlägg
#3

Lasp skrev:

Ett telefon nummer har alltid ytterligare en begränsning, det gäller from - tom, för en viss kund.

Jag sa att det var ett dåligt exempel jag ville bara förklara problematiken med många till många relationer.

NickemannenMedlem sedan aug. 20003 575 inlägg
#4

Hmm jag tror jag kom på ett av problemen och det är Contains, om Contains funktionen använder object.equals(obj). Så kan man override:a equals och göra en egen. Som jämför ID:n i detta fall.

PMedlem sedan jan. 20012 204 inlägg
#5

Lazy-loading kanske. Läs inte in någon data innan du behöver det, då loopar du inte runt i oändligheten i alla fall.

NickemannenMedlem sedan aug. 20003 575 inlägg
#6

Jo jag har läst lite om Lazy-loading, har funderat på hur man skall använda det. Det skulle kunna vara en tänkbar lösning.

JonMedlem sedan juli 20011 304 inlägg
#7

Som jag ser det så beor det helt och hållet på hur du väljer att koda ditt BLL och i viss mån ditt DAL.

En möjlig väg att gå:
Om vi antar att du vill jobba med domändriven metodik av något slag så har du förmodligen en CustomerRepository och en PhonenumberRepository (Som sagt lite udda men bara ett exempel, kanske bra på t.ex eniro)

Du kan då låta

Customer c = CustomerRepository.GetCustomerById(666);

fylla på customer med dess data och samtidigt fylla dess Phonenumber-objekt.

Vill du sedan komma åt alla andra som detta telefonnummer pekar på så ropar du på

PhoneNumber pn = PhoneNumberRepository.GetPhoneNUmberById(c.PhoneNumbers[13].ID);

vilken skulle kunna fyllapå sig och alla Customers den aggregerar.

En annan väg att gå är den med lazy-loading, men då kan man få problemet som är själva grundfrågan: vad händer om 2 lazy-loadande klasser ropar på varandra? Jo : är det en komplex objektmodell med många beroenden kan det sluta med att man har läst in hela databasen i minnet. Man kan tänkta sig lite mer avancerade modeller där en lazy-loadande metod alltid tar med sig en flagga som berättar att det inte skall laddas vidare saker. Personligen gillar jag inte riktigt det eftersom koden kan bli svårförstådd och rörig.

Arbetar man med en O/R mapper av lite grövre kaliber brukar den göra objektgarfer och räkna ut hur saker skall laddas med hjälp av sitt metadata.

Personligen gillar jag att lägga en extra tanke på det som jag tycker är grunden i objektorienterineg, nämligen: Vem skall ha ansvaret för att ladda in information i mina objekt?

Klokare? Eller bara förvirrande? :)

En sak jag funderade på är dock vilken din tredje entitet är och vad du ska ha den till? Relationstabellen bör i min mening inte bli egna objekt (io alla fall inte som syns). Eller menar du kanske något annat?

NickemannenMedlem sedan aug. 20003 575 inlägg
#8

Hmm, jo jag funderar också på detta, men lägger man ansvaret på en speciell klass blir det inte så konsekvent som man kanske önskat,

Jo detta med den tredje entiteten (index) känns inte som man borde ha med som en egen klass, man kanske skulle skapat den och lagt med den dock, läste något som faktiskt stämmer på en annan sida att i vissa fall kanske man lägger till saker till entiteten (indextabellen) och då vill man ju inte behöva jobba om alltihoppa.

JonMedlem sedan juli 20011 304 inlägg
#9

Hmm, jo jag funderar också på detta, men lägger man ansvaret på en speciell klass blir det inte så konsekvent som man kanske önskat

Jag tycker att det är mycket tydligare att låta min klass som hanterar Kunder hämta dom enligt mina regler än att generellt säga load på en kund och sen veta att den egentligen skall ladda sin egen data i sig själv och kanske göra lite andra grejjer med.

Det hela beror på hur du ser Customer: som ett objekt eller en klass. Ser du den som en klass är det läge att låta den sköta saker. Det jag tycker blir otydligt med det synsättet är att den sedan fyller på sig själv med data och agerar både datahållare och datahämtare och dessutom affärslogik-hanterare. Ber du en kund att ladda kund med id 7 känns det som om du ber om en annan kund, som han sen blir. Eller ber du en kund att ladda sig själv? Kanske - rörigt? Han fanns ju inte - hur och varför skulle han ladda sig själv? beror som sagt på smak och tycke. Jag påstår inte att det är fel - bara att just jag inte tänker riktigt så.

Ser man Customer som ett objekt tycker jag att den ska hålla sig till det den är, nämligen en kund, inte en kundhanterare.

Däremot finns det saker jag tycker hör hemma på objektet i alla lägen: nämligen specifika affärsregler för just denna objekttyp, typ Customer.GetSpecialDiscount() och sådant.

Jo detta med den tredje entiteten (index) känns inte som man borde ha med som en egen klass, man kanske skulle skapat den och lagt med den dock, läste något som faktiskt stämmer på en annan sida att i vissa fall kanske man lägger till saker till entiteten (indextabellen) och då vill man ju inte behöva jobba om alltihoppa.

Jag tycker inte att du ska göra egna objekt för relationstabeller. Även dettaborde skötas av antingen Objektet eller dess hanterare , dvs

Customer.AddAddress(AddressObject a);
Customer.AddAddress(int AddressObjectId);
Customer.RemoveAddress(AddressObject a);
Customer.RemoveAddress(int AddressObjectId);

eller

CustomerHandler.AddAddressToCustomer(Customer c, AddressObject a);
CustomerHandler.AddAddressToCustomer(int CustomerId , int AddressObjectId);
CustomerHandler.RemoveAddressFromCustomer(Customer c, AddressObject a);
CustomerHandler.RemoveAddressFromCustomer(int CustomerId , int AddressObjectId);

Man talar ofta om att man vill ha high cohesion (samanhållning) och low coupling (koppling) inom OO-metodiker. Att låta ett CustomerObject behöva veta om andra objekts sammanstättning och ta bort/lägga till dessa är exempel på high coupling och inte önskvärt, därför använder man service-klasser och factories. Sen ser inte alltid verkligheten ut som teorin vill beskriva det, det finns ju alltid fler faktorer att ta hänsyn till men jag anser att många kloka människor har tänkt till ordentligt kring setta och om man kan så ska man i alla fall överväga att göra på detta viset ;)

NickemannenMedlem sedan aug. 20003 575 inlägg
#10

Jag håller med dig fullständigt.

Det exemplet som jag läste om där relationsobjektet skulle ingå var ett skolexempel där entiteterna var Student, Cource, CourseTaken,
Där innehåll CourseTaken inte bara studentid, courseid utan också vilket datum osv... det var det jag menade med tänk om man i början bara ser relationen och efter ett år eller två helt plötsligt kommer på att oj vi vill ha mer data i relationen då kan det bli mycket jobb att göra om. Och var/hur skulle man då lagra detta... antar att man skulle få skapa ett objekt med CourseTaken och lagrat istället och tvärtom.

Men jag håller med dig det blir fult rent OOP att inkludera index tabellerna som ett objekt jag tycker också man skall ha ha en lista i Customer i detta fallet.

134 ms totalt · 3 externa anrop · v20260731065814-full.0e50b1ef
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
132 ms — hämta tråd, inlägg och bilagor (db)