Ваша ассоциация должна быть двунаправленной, как указано в документации Hibernate.
У этой стратегии много недостатков (особенно
с полиморфными запросами и
ассоциации) объяснил в JPA
спецификация, ссылка на Hibernate
документация, Hibernate в действии,
и много других мест. Спящая работа
вокруг большинства из них реализуют это
стратегия с использованием запросов SQL UNION. Это
обычно используется для верхнего уровня
иерархия наследования:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Flight implements Serializable { ... }
Эта стратегия поддерживает один ко многим
ассоциации при условии, что они
Двунаправленный . Эта стратегия делает
не поддерживает генератор IDENTITY
стратегия: идентификатор должен быть разделен
через несколько столов. Как следствие,
при использовании этой стратегии, вы должны
не используйте ни AUTO, ни IDENTITY.
Таким образом, Hibernate сможет создать соответствующий столбец внешнего ключа в каждой конкретной таблице виджетов. Вот карта, которая на самом деле работает. Для Container
:
@Entity
public class Container {
@Id @GeneratedValue
private long id;
@OneToMany(targetEntity = Widget.class, mappedBy = "container", cascade = CascadeType.ALL)
private Set<Widget> widgets = new HashSet<Widget>();
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public Set<Widget> getWidgets() { return widgets; }
public void setWidgets(Set<Widget> widgets) { this.widgets = widgets; }
public void addToWidgets(Widget widget) {
this.getWidgets().add(widget);
widget.setContainer(this);
}
public void removeFromWidgets(Widget widget) {
this.getWidgets().remove(widget);
widget.setContainer(null);
}
}
И абстрактный класс Widget:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Widget {
@Id @GeneratedValue(strategy = GenerationType.TABLE)
private long id;
private int position;
@ManyToOne
private Container container;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public int getPosition() { return position; }
public void setPosition(int position) { this.position = position; }
public Container getContainer() { return container; }
public void setContainer(Container container) { this.container = container; }
}
И следующий метод тестирования (запущенный внутри транзакции) просто проходит:
@Test
public void testInsertContainer() {
TextWidget textw1 = new TextWidget();
ImageWidget imgw1 = new ImageWidget();
Container container1 = new Container();
container1.addToWidgets(textw1); // instance of TextWidget
container1.addToWidgets(imgw1); // instance of ImageWidget
session.persist(container1);
session.flush();
assertNotNull(textw1.getId());
assertNotNull(imgw1.getId());
assertNotNull(container1.getId());
}
И генерирует следующий SQL:
21:59:57.964 [main] DEBUG org.hibernate.SQL - select next_hi from hibernate_unique_key for read only with rs
21:59:57.978 [main] DEBUG org.hibernate.SQL - update hibernate_unique_key set next_hi = ? where next_hi = ?
21:59:58.063 [main] DEBUG org.hibernate.SQL - null
21:59:58.125 [main] DEBUG org.hibernate.SQL - insert into Container (id) values (?)
Hibernate: insert into Container (id) values (?)
21:59:58.140 [main] TRACE org.hibernate.type.LongType - binding '98304' to parameter: 1
21:59:58.145 [main] DEBUG org.hibernate.SQL - insert into ImageWidget (container_id, position, id) values (?, ?, ?)
Hibernate: insert into ImageWidget (container_id, position, id) values (?, ?, ?)
21:59:58.164 [main] TRACE org.hibernate.type.LongType - binding '98304' to parameter: 1
21:59:58.165 [main] TRACE org.hibernate.type.IntegerType - binding '0' to parameter: 2
21:59:58.166 [main] TRACE org.hibernate.type.LongType - binding '32768' to parameter: 3
21:59:58.172 [main] DEBUG org.hibernate.SQL - insert into TextWidget (container_id, position, id) values (?, ?, ?)
Hibernate: insert into TextWidget (container_id, position, id) values (?, ?, ?)
21:59:58.187 [main] TRACE org.hibernate.type.LongType - binding '98304' to parameter: 1
21:59:58.188 [main] TRACE org.hibernate.type.IntegerType - binding '0' to parameter: 2
21:59:58.189 [main] TRACE org.hibernate.type.LongType - binding '32769' to parameter: 3
Но имейте в виду, что стратегия таблицы на класс обеспечивает слабую поддержку полиморфных отношений и может быть не совсем уместной, если у вас много детей Widget
(это приведет к в огромном SQL UNION).
Смежный вопрос