-->

How to map collection of each subclass from same h

2019-04-13 21:33发布

问题:

Does anyone know how to map a collection of each subclass from the same hierarchy onto one owning class, using JPA 2.0 annotations, backed by Hibernate 4.0.0.Final?

Bit convoluted, so here's an example. Hierarchy classes look like this:


    @Entity
    @Cacheable(true)
    @Table(name = "hierarcicals")
    @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "class", discriminatorType = DiscriminatorType.STRING)
    public abstract class MySuperClass {
    ...

    @Entity
    @DiscriminatorValue("SubClassOne")
    public class SubClassOne extends MySuperClass {
    ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "owner")
    private Owner owner;

    @Entity
    @DiscriminatorValue("SubClassTwo")
    public class SubClassTwo extends MySuperClass {
    ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "owner")
    private Owner owner;

This all looks fine, and when I persist objects, I can see them going into the database with the right discriminators, and the right owner.

Here's my 'owning' class - nothing special about its annotations:

@Entity
@Cacheable(true)
@Table(name = "owner")
public class Owner  {
...
@OneToMany(mappedBy = "owner", fetch = FetchType.LAZY)
private List<SubClassOne> subClassOnes;

@OneToMany(mappedBy = "owner", fetch = FetchType.LAZY)
private List<SubClassTwo> subClassTwos;
...

The 2 List collections have getters. When I call getSubClassOnes(), I get a bag of ALL the associated entities back, as type SubClassOne, even those that have the SubClassTwo discriminator in the database. When I call getSubClassTwos(), I get what appears to be a bag of SubClassTwos, but which, when I iterate over the collection at runtime, blows up with

org.hibernate.WrongClassException: Object with id: gM4pnnoRge4Odx4lUTZNMQ was not of the specified subclass: my.package.SubClassTwo (loaded object was of wrong class class my.package.SubClassOne) at org.hibernate.loader.Loader.instanceAlreadyLoaded(Loader.java:1420) [hibernate-core-4.0.0.Final.jar:4.0.0.Final] at org.hibernate.loader.Loader.getRow(Loader.java:1373) [hibernate-core-4.0.0.Final.jar:4.0.0.Final] at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:640) [hibernate-core-4.0.0.Final.jar:4.0.0.Final] at org.hibernate.loader.Loader.doQuery(Loader.java:856) [hibernate-core-4.0.0.Final.jar:4.0.0.Final] at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:289) [hibernate-core-4.0.0.Final.jar:4.0.0.Fin at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259) [hibernate-core-4.0.0.Final.jar:4.0.0.Fin at org.hibernate.loader.Loader.loadCollection(Loader.java:2175) [hibernate-core-4.0.0.Final.jar:4.0.0.Final] at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:61) [hibernate-core-4.0.0.Final.jar:4.0.0.F at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:622) [hibernate-co at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEvent at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1606) [hibernate-core-4.0.0.Final.jar:4.0.0.Final] at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:379) [hibernate-c at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:112) [hibernate-core-4. at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:266) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]

What I'd like to happen is that getSubClassOnes() returns a collection containing those associated with the owner with class SubClassOnes, and getSubClassTwos() returns a collection with the relevant SubClassTwos. Does anyone know how I can achieve this?

回答1:

For us this was fixed by adding the targetEntity attribute to the @OneToMany annotation, pointing to the super class, like so:

@OneToMany(mappedBy = "owner", fetch = FetchType.LAZY, targetEntity = MySuperClass.class)
private List<SubClassOne> subClassOnes;

@OneToMany(mappedBy = "owner", fetch = FetchType.LAZY, targetEntity = MySuperClass.class)
private List<SubClassTwo> subClassTwos;