2013-06-04 4 views
0

У меня проблема с наложением JPA. См. Мои сущности ниже. У меня есть Person, который может быть либо в House, либо в Car, но в то же время, конечно. Оба Car и House реализуют интерфейс PersonHoldable. Я знаю, что не могу сопоставить Entity напрямую с интерфейсом.JPA Наследование, отображающее множественные реализации

Это моя модель:

@Entity 
public class Person{ 
    private PersonHoldable personHoldable; // either a Car or a House 

    // This does not work of course because it's an interface 
    // This would be the way to link objects without taking JPA into consideration. 
    @OneToOne 
    public PersonHoldable getPersonHoldable() { 
    return this.personHoldable; 
    } 

    public void setPersonHoldable(PersonHoldable personHoldable) { 
    this.personHoldable = personHoldable; 
    } 
} 

@Entity 
public class Car implements PersonHoldable{} 

@Entity 
public class House implements PersonHoldable{} 

public interface PersonHoldable{} 

Как я могу отобразить это правильно в JPA принимая во внимание следующее?

  1. Я пробовал @MappedSuperclass об абстрактной реализации PersonHoldable. Хотя это будет работать для этой конкретной установки, проблема заключается в том, что Car и House на самом деле реализуют больше интерфейсов. И они сопоставляются с другими объектами.
  2. У Person может быть имущество для всех возможных PersonHoldable, поэтому в этом случае у него могут быть и getHouse(). Мне это не кажется очень гибким. Если бы я добавил Bike, то мне пришлось бы изменить класс Person.
  3. Я могу сопоставить обратное, так что отношение OneToOne относится только к стороне реализации PersonHoldable. Это означало бы добавление свойства getPerson() к PersonHoldable. Но с точки зрения Person это не очень просто, чтобы увидеть, с чем связано PersonHoldable.
  4. Я использую JPA по умолчанию, поэтому, по возможности, никаких тегов Hibernate нет.

Если это невозможно при использовании JPA по умолчанию, что было бы лучше всего в этом случае?

+1

Это не поддерживается стандартной JPA. Для сопоставления такой ассоциации понадобится сопоставление hibernate '@ Any'. –

+0

Спасибо, кажется, Hibernate '@ Any' - это всего лишь два столбца, один из которых содержит« тип »и один, содержащий« id ». Может быть реализовано вручную. Это обычная практика? –

+1

Это «ничего более», за исключением того, что он генерирует все соответствующие запросы для вас, например, «выберите p из Person p left join fetch p.personHoldable», и он позволяет перейти к personHoldable, не заботясь о том, какой он тип. Используется ли такая практика? Мне никогда не приходилось использовать его сам. Я бы предпочел определить абстрактный объект, который будет расширяться всеми объектами PersonHoldable. Это будет стандартная JPA. –

ответ

1

Незначительное изменение в вашей второй точке должно заключаться в том, чтобы заставить Person иметь тип наследования и реализовать CarPerson и HousePerson (и позже BikePerson), цель которого - определить конкретное отношение соединения к конкретной реализации PersonHolder. Это сохраняет отношения неповрежденными и более легко запрашиваемыми с Личности.

@Inheritance(strategy = JOINED) 
@DiscriminatorColumn(name="holdableType", discriminatorType=CHAR, length=1) 
@Entity 
public class Person { 
    // common fields 
} 

@Entity 
@DiscriminatorValue("C") 
public class CarPerson extends Person { 
    @OneToOne 
    private Car car; 
} 

@Entity 
@DiscriminatorValue("H") 
public class HousePerson extends Person { 
    @OneToOne 
    private House house; 
} 
+0

Это делает невозможным изменение места, где он живет. Когда-то это CarPerson, это CarPerson и не может стать HousePerson. Я предпочел бы использовать наследование для стороны PersonHoldable. –

+0

Как только это CarPerson, у него есть данные, связанные с ним в таблице, связанной с автомобилем. Неспособность быстро перейти к HousePerson является фактором этого, а не иерархии объекта. Если есть потребность в бизнесе, чтобы переместиться между CarPerson и HousePerson, что легко можно выполнить с помощью фабричного метода, который соответствующим образом обрабатывает уровень сохранения. Я бы сказал, что кто-то может одновременно быть как автомобилем, так и домашним человеком, но вопрос, как написано, явно указывает на отношения 1-1. – Jeff

+0

проблема не связана с тем, что они хранятся в разных таблицах. Даже с наследованием с одной таблицей у вас возникнет эта проблема, вызванная тем, что объект данного типа не может стать объектом другого типа в Java. Таким образом, единственный способ изменить тип - удалить человека и заново создать его как другой тип (не работает, если есть внешние ключи для человека), или использовать JDBC для перемещения строки из одной таблицы в другую или для изменения значения дискриминатора в строке в случае наследования с одной таблицей. –