Определение нескольких свойств Address в Person для AddressType с помощью таблицы тройного соединения - PullRequest
12 голосов
/ 03 октября 2010

У меня есть база данных с отношением PERSON - ADDRESS - ADDRESS_TYPE, поддерживаемым таблицей тройного соединения PERSON_ADDRESS. Соотношение PERSON - ADDRESS фактически одно-ко-многим.

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

По практическим соображениям я бы хотел, чтобы моя сущность Person заканчивалась следующим образом:

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

Возможно ли это когда-нибудь с аннотациями JPA 2.0?

Я прочитал главу Key Key Columns JPA wikibook , и мне кажется, что я должен использовать @MapKeyJoinColumn, но мне не совсем понятно, как успешно использовать его в этой ситуации. Я ожидал увидеть пример @JoinColumn вдоль него, но он отсутствует в фрагментах кода в вики-книге.

Если это невозможно с @MapKeyJoinColumn, тогда альтернативный подход с помощью возможно @MapKeyClass на Map<AddressType, Address> также приветствуется, пока я могу получить getHomeAddress() и getOfficeAddress() в сущности Person.

1 Ответ

11 голосов
/ 03 октября 2010

При условии, что у вас есть два предопределенных AddressType с, когда другие могут быть добавлены, работает следующий подход с @MapKeyJoinColumn:

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);
    }
}

Итак, у вас есть предопределенные методы для предопределенных типов адресов, когда другие типы могут использоваться через прямой доступ к карте. orphanRemoval используется для реализации setHomeAddress(null) поведения. @ElementCollection не будет работать здесь, потому что он не поддерживает таблицу соединений.

...