2010-10-03 7 views
12

Ich habe hier eine Datenbank mit einer PERSON - ADDRESS-ADDRESS_TYPE Beziehung durch eine dreifache gehaltene Tisch sitzt PERSON_ADDRESS. Die PERSON - ADDRESS Beziehung ist effektiv eins zu viele.definieren mehrere Eigenschaften Adresse in Person pro Address durch eine Tabelle triple beitreten

PERSON

 
ID FIRSTNAME LASTNAME 
-- --------- -------- 
1 John  Doe 
2 Jane  Doe 

ADDRESS

 
ID STREET    CITY 
-- -------------------- ------------- 
1 Home Street 1  Hometown 
2 Office Street 1  Officetown 
3 Main Street 1  Maintown 
4 Business Building 1 Businesstown 

ADDRESS_TYPE

 
ID NAME 
-- --------------- 
1 Home Address 
2 Office Address 

PERSON_ADDRESS

 
PERSON_ID ADDRESS_TYPE_ID ADDRESS_ID 
--------- --------------- ---------- 
1   1    1 
1   2    2 
2   1    3 
2   2    4 

Aus praktischen Gründen würde Ich mag meine Person Einheit haben, um am Ende wie:

public class Person { 
    private Address homeAddress; // Insertable/updateable by ADDRESS_TYPE_ID=1 
    private Address officeAddress; // Insertable/updateable by ADDRESS_TYPE_ID=2 
} 

Ist das überhaupt möglich mit JPA 2.0 Anmerkungen?

Ich habe die Map Key Columns chapter of the JPA wikibook gelesen und es scheint, dass ich eine @MapKeyJoinColumn verwenden muss, aber es ist mir nicht ganz klar, wie man es in dieser Situation erfolgreich verwendet. Ich habe erwartet, ein Beispiel zu sehen, aber es ist nicht in den Code-Schnipsel im Wikibook.

Wenn das nicht möglich ist, mit @MapKeyJoinColumn, dann einem alternativen Ansatz mit Hilfe von vielleicht @MapKeyClass auf einem Map<AddressType, Address> ist auch willkommen, solange ich mit einem getHomeAddress() und getOfficeAddress() in der Person Einheit kann am Ende.

+0

Verwenden Sie eine Enum für ADDRESS_TYPE? Weil das sinnvoll wäre, da Sie feste Adressentypen zur Kompilierung haben wollen. – Bozho

+0

@Bozho: Ich habe es noch nicht vollständig implementiert, aber wenn es möglich ist, würde die Verwendung eines '@ Enumerated' definitiv meine Präferenz haben, ja. – BalusC

+0

aha. Und was ist dein Ausdaueranbieter? (Providerspezifische Anmerkungen sind als letzter Ausweg erlaubt, denke ich) – Bozho

Antwort

11

Unter der Annahme, dass Sie zwei vordefinierte AddressType s haben, wenn andere hinzugefügt werden können, den folgenden Ansatz mit @MapKeyJoinColumn Werke:

public class AddressType { 
    public static final AddressType HOME = new AddressType(1L, "Home"); 
    public static final AddressType OFFICE = new AddressType(2L, "Office"); 
    ... 
    ... hashCode, equals based on id ... 
} 

public class Person { 
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) 
    @JoinTable(name = "PERSON_ADDRESS", 
     joinColumns = @JoinColumn(name = "PERSON_ID"), 
     inverseJoinColumns = @JoinColumn(name = "ADDRESS_ID")) 
    @MapKeyJoinColumn(name = "ADDRESS_TYPE_ID") 
    private Map<AddressType, Address> addresses = new HashMap<AddressType, Address>(); 
    ... 
    public Address getHomeAddress() { 
     return getAddress(AddressType.HOME); 
    } 

    public void setHomeAddress(Address a) { 
     setAddress(AddressType.HOME, a); 
    } 
    ... 

    public void setAddress(AddressType type, Address a) { 
     if (a == null) { 
      addresses.remove(type); 
     } else { 
      addresses.put(type, a); 
     }  
    } 

    public Address getAddress(AddressType type) { 
     return addresses.get(type); 
    } 
} 

So haben Sie vordefinierte Methoden für vordefinierte Adresstypen, wenn andere Typen können über verwendet werden direkter Zugriff auf die Karte. orphanRemoval wird verwendet, um setHomeAddress(null) Verhalten zu implementieren. @ElementCollection würde hier nicht funktionieren, da es Join-Tabelle nicht unterstützt.

+0

Oh Junge, es funktioniert :) Vielen Dank. Ich habe in der Zwischenzeit auch gevögelt, aber ich hatte das '@ JoinTable' komplett falsch gemacht. Es macht jetzt auch mehr Sinn. Ich bin allerdings neugierig, ob es auch mit einem 'enum AddressType' möglich ist. – BalusC

+0

sehr gut, +1 :) – Bozho

+0

@BalusC: Ich denke, Sie können 'enum' nicht verwenden, wenn Sie Ihr DB-Schema ändern. Sie können entweder 'enum' oder entity verwenden, die der Tabelle 'ADDRESS_TYPE' zugeordnet sind. – axtavt