Ik heb een vraag over een questie bij het mappen van een object naar een relationele database. Nu heb ik de werking daarvan verborgen achter repositories (zoals in het boek Domain-Driven Design wordt voogesteld), zodat de werkelijke opslag methode wordt verborgen voor de domein objecten. Nu heb ik alleen een probleem bij het mappen van een geaggregeerd object. Op zich is het geen probleem, alleen vind ik het niet netjes. Het probleem is dat een bezittend object vaak een refefentie heeft naar het bezeten object, maar andersom niet. In het geval van een tabel in een relationele database is dat juist precies andersom. (Vooral in het geval van meerdere bezeten objecten.) Nu heb ik een probleem dat het bezeten object vaak toch een referentie naar zijn bezitter nodig heeft, omdat bij het mappen een waarde voor de foreign key nodig is. En de referentie wordt dan vaak verder helemaal nergens anders voor gebruikt. Nu is mijn vraag hoe jullie dat oplossen.
Een stukje voorbeeld code ter illustratie.
Nu zijn er bepaalde problemen met deze code.
Sowieso kan dit in princiepe helemaal niet, omdat een Order een Customer object vraagt in de constructor en Customer op zijn beurt weer een collectie Orders. Dit is uiteraard op te lossen door een setter setCustomer toe te voegen aan Order of een setter setOrders aan Customer. Beide wil ik liever niet. Om dat op te lossen moet de Customer referentie weg uit Order. (OK, mischien heeft een Order dat in een werkelijk applicatie wel nodig, maar ga er maar even vanuit dat het niet zo is, het is voor het voorbeeld niet van belang.) Maar dat zorgt er dus voor dat de store functie niet goed werkt in OrderRepository. Nu kan ik wel een functie toevoegen als addOrderToCustomer(), maar is dat wel zo netjes?
Je zou kunnen beargumenteren dat je een CustomerRepository puur de verantwoordelijkheid moet geven over het opslaan van Orders, maar als Orders los onafhankelijk van de Customer aan de hand van hun ID opgehaald moeten kunnen worden (wat waarschijnlijk zo is), dan gaat dat al niet.
Een andere mogelijke oplossing is om een Proxy of Decorator te maken voor OrderCollection welke de taak heeft om het customer_id veld in de orders tabel op de juiste waarde te zetten. OrderRepository zelf heeft dan alleen de taak om alle velden die direct met Order te maken hebben een waarde te geven. (Voor het voorbeeld alleen id en name dan.) Op zich heb ik al proxies voor veel collectie classes (die lazy loading functionaliteit bevatten), dus dat zou op zich een redelijk oplossing kunnen zijn. Alleen vereist dit wel dat per toegevoegde order 2 in plaats van 1 query uitgevoerd moet worden.
Hoe denken jullie hier over? Door al die bidirectional associations krijg je een heel net met koppelingen. Maak ik me te veel zorgen om niets of is dit wel iets om aandacht aan te besteden?
Een stukje voorbeeld code ter illustratie.
code:
1
2
3
4
5
| tabel: customers velden: id, name tabel: orders velden: id, customer_id, name |
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| class Customer
{
public Customer(int ID, String name, OrderCollection orders)
{
this.ID = ID;
this.name = name;
this.orders = orders;
}
private int ID;
public int getID()
{
return ID;
}
private String name;
public String getName()
{
return name;
}
private OrderCollection orders;
public OrderCollection getOrders()
{
return orders;
}
public Order addNewOrder(int ID, String name)
{
Order order = new Order(ID, name, this);
orders.add(order);
OrderRepository.store(order);
}
}
class Order
{
public Order(int ID, String name, Customer customer)
{
this.ID = ID;
this.name = name;
this.customer = customer;
}
private int ID;
public int getID()
{
return ID;
}
private String name;
public String getName()
{
return name;
}
private Customer customer;
public Customer getCustomer()
{
return customer;
}
}
class OrderRepository
{
public static void store(Order order)
{
int customer_id = order.getCustomer().getID();
// in de database voegen met deze waarde
}
} |
Nu zijn er bepaalde problemen met deze code.
Sowieso kan dit in princiepe helemaal niet, omdat een Order een Customer object vraagt in de constructor en Customer op zijn beurt weer een collectie Orders. Dit is uiteraard op te lossen door een setter setCustomer toe te voegen aan Order of een setter setOrders aan Customer. Beide wil ik liever niet. Om dat op te lossen moet de Customer referentie weg uit Order. (OK, mischien heeft een Order dat in een werkelijk applicatie wel nodig, maar ga er maar even vanuit dat het niet zo is, het is voor het voorbeeld niet van belang.) Maar dat zorgt er dus voor dat de store functie niet goed werkt in OrderRepository. Nu kan ik wel een functie toevoegen als addOrderToCustomer(), maar is dat wel zo netjes?
Je zou kunnen beargumenteren dat je een CustomerRepository puur de verantwoordelijkheid moet geven over het opslaan van Orders, maar als Orders los onafhankelijk van de Customer aan de hand van hun ID opgehaald moeten kunnen worden (wat waarschijnlijk zo is), dan gaat dat al niet.
Een andere mogelijke oplossing is om een Proxy of Decorator te maken voor OrderCollection welke de taak heeft om het customer_id veld in de orders tabel op de juiste waarde te zetten. OrderRepository zelf heeft dan alleen de taak om alle velden die direct met Order te maken hebben een waarde te geven. (Voor het voorbeeld alleen id en name dan.) Op zich heb ik al proxies voor veel collectie classes (die lazy loading functionaliteit bevatten), dus dat zou op zich een redelijk oplossing kunnen zijn. Alleen vereist dit wel dat per toegevoegde order 2 in plaats van 1 query uitgevoerd moet worden.
Hoe denken jullie hier over? Door al die bidirectional associations krijg je een heel net met koppelingen. Maak ik me te veel zorgen om niets of is dit wel iets om aandacht aan te besteden?