У меня есть следующая корневая сущность СОЕДИНЕННОГО наследования для географических областей (например, континентов, стран, штатов и т. Д.):
@Entity
@Table(name = "GeoAreas")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class GeoArea implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
protected Integer id;
@Column
protected String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id", referencedColumnName = "id")
protected GeoArea parent;
...
}
Как вы можете видеть, географическая область имеет простой автоидентификатор, такой как PK, имя и отношение к своему родителю (ссылка на себя). Пожалуйста, обратите внимание на отношение parent
географической области, обозначенное как FetchType.LAZY
. В БД parent_id
FK NOT NULL
делает отношения необязательными. По умолчанию для @ManyToOne
установлено optional = true
, поэтому сопоставления выглядят правильными.
Подклассы определяют дополнительные свойства и на самом деле не представляют интереса. Данные в БД правильно связаны, так как географические области можно без проблем перечислить через JPQL (с немного другим отображением FetchType.EAGER
на parent
, см. Конец текста):
![Arena list with EAGER loading](https://i.stack.imgur.com/zrgJR.png)
Каждая строка является экземпляром:
public class ArenaListViewLine
{
private final Integer arenaId;
private final String arenaName;
private final String arenaLabel;
private final Boolean hasPostAddress;
...
public ArenaListViewLine(Arena arena, Boolean hasPostAddress)
{
// init fields
...
List<String> continentNames = new ArrayList<String>();
List<String> countryNames = new ArrayList<String>();
List<String> regionNames = new ArrayList<String>();
List<String> stateNames = new ArrayList<String>();
List<String> districtNames = new ArrayList<String>();
List<String> clubShorthands = new ArrayList<String>();
// add each geo area to list whose club is a user of an arena (an arena has several usages)
// in border areas of states two clubs from different states might use an arena (rare!)
// this potentially adds several states to an entry in the arena list (non in DB yet)
for ( Usage us : usages )
{
Club cl = us.getClub();
// a club is located in one district at all times (required, NOT NULL)
District di = cl.getDistrict();
System.out.println("arena = " + arenaName + ": using club's district parent = " + di.getParent());
State st = (State)di.getParent(); // ClassCastException here!
...
}
...
}
При выполнении запроса списка с родителем, сопоставленным как LAZY, я получаю следующее исключение:
...
Caused by: org.hibernate.QueryException: could not instantiate class [com.kawoolutions.bbstats.view.ArenaListViewLine] from tuple
at org.hibernate.transform.AliasToBeanConstructorResultTransformer.transformTuple(AliasToBeanConstructorResultTransformer.java:57) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:95) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.loader.hql.QueryLoader.getResultList(QueryLoader.java:438) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2279) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.loader.Loader.list(Loader.java:2274) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:196) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1115) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:252) [hibernate-entitymanager-4.0.0.Final.jar:4.0.0.Final]
... 96 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [:1.7.0_02]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) [:1.7.0_02]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) [:1.7.0_02]
at java.lang.reflect.Constructor.newInstance(Unknown Source) [:1.7.0_02]
at org.hibernate.transform.AliasToBeanConstructorResultTransformer.transformTuple(AliasToBeanConstructorResultTransformer.java:54) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
... 106 more
Caused by: java.lang.ClassCastException: com.kawoolutions.bbstats.model.GeoArea_$$_javassist_273 cannot be cast to com.kawoolutions.bbstats.model.State
at com.kawoolutions.bbstats.view.ArenaListViewLine.<init>(ArenaListViewLine.java:92) [classes:]
... 111 more
Печать до трассировки стека:
13:57:47,245 INFO [stdout] (http--127.0.0.1-8080-4) arena = Joachim-Schumann-Schule: using club's district parent = com.kawoolutions.bbstats.model.State@2b60693e[id=258,name=Hesse,isoCode=HE,country=com.kawoolutions.bbstats.model.Country@17f9976b[id=88,name=Germany,isoCode=DE,isoNbr=276,dialCode=<null>]]
В печати ясно сказано, что родитель является экземпляром State, но его нельзя передать в State? Понятия не имею ...
При изменении FetchType для GeoArea.parent на EAGER все работает нормально (см. Изображение выше).
Что я делаю не так? Что не так с ленивым намеком?
Спасибо
PS: я использую Hibernate 4.0.0.Final , все сопоставления - стандартные JPA, сервер - JBoss AS 7.