tags:

views:

51

answers:

1

I am trying to map a JPA (using Hibernate) one-to-one relationship with a inheritance strategy TABLE_PER_CLASS. Here is an example:

@Entity
public class DrivingLicense {

    @OneToOne(targetEntity = Human.class, cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinColumn
    private Human human;

    @SuppressWarnings("unchecked")
    public static List<DrivingLicense> findMansDrivingLicenses(Long id) {
        if (id == null) return null;
        return entityManager()
            .createQuery("select o from DrivingLicense o left join fetch o.human where o.id = :id")
            .setParameter("id", id)
            .getResultList();
    }

}

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Human {
   ...
}

@Entity
public class Man extends Human {
   ...
}

@Entity
public class Mutant extends Human {
   ...
}

When I call "findMansDrivingLicenses" to retrieve all man's driving licenses hibernate does a "UNION ALL" with both tables (MAN and MUTANT). Follow the log output:

select
        drivinglic0_.id as id3_0_,
        human1_.id as id0_1_,
        drivinglic0_.first_name as first2_3_0_,
        drivinglic0_.human as human3_0_,
        drivinglic0_.last_name as last3_3_0_,
        drivinglic0_.type as type3_0_,
        drivinglic0_.version as version3_0_,
        human1_.version as version0_1_,
        human1_.comment as comment1_1_,
        human1_.behavior as behavior2_1_,
        human1_.clazz_ as clazz_1_ 
    from
        driving_license drivinglic0_ 
    left outer join
        (
            select
                id,
                version,
                comment,
                null as behavior,
                1 as clazz_ 
            from
                man 
            union
            all select
                id,
                version,
                null as comment,
                behavior,
                2 as clazz_ 
            from
                mutant 
        ) human1_ 
            on drivinglic0_.human=human1_.id 
    where
        drivinglic0_.id=?

Is there any way to prevent hibernate to do this "UNION ALL" and only join with MAN table?

A: 

Try to use class

select o from DrivingLicense o left join fetch o.human human where o.id = :id and human.class = Man

UPDATE

retrieve your relationship with Native queries

session = sessionFactory.openSession();

StringBuilder query = new StringBuilder();
query
.append("select ")
    .append("{driving.*}, {man.*} ")
.append("from ")
    .append("DrivingLicense driving ")
.append("left join ")
    .append("Man man ")
.append("on ")
    .append("driving.human_id = man.id ")
.append("where ")
    .append("driving.id = :id");

Query _query = session.createSQLQuery(query.toString())
                      /**
                        * It means: driving alias WILL BE MAPPED TO DrivingLicense Entity
                        */
                      .addEntity("driving", DrivingLicense.class)
                      /**
                        * It means: man alias WILL BE MAPPED TO human property of DrivingLicense Entity
                        */
                      .addJoin("man", "driving.human")
                      .setParameter("id", <DRIVING_LICENSE_ID_GOES_HERE>);


Object [] resultArray = query.list.get(0);

session.close();

And

DrivingLicense driving = resultArray[0];
/**
  * YES, Man IS NOT automatically MAPPED TO driving.human property
  * You have to set up manually
  */
Man man = resultArray[1];

driving.setHuman(man);
Arthur Ronald F D Garcia
Query modified, still joining (union all) with tables man and mutant :( Added @org.hibernate.annotations.Entity(polymorphism = PolymorphismType.EXPLICIT) and nothing too!
monit06
@monit06 I am pertty sure It occurs because you have a **TABLE_PER_CLASS** strategy. Because **identity must be guaranteed**, Hibernate makes sure all of subclasses does not return The same identity. If you really want to avoid this kind of behavior you should use MappedSuperclass instead of inheritance.
Arthur Ronald F D Garcia
@monit06 Or use **SINGLE_TABLE** strategy. JOINED strategy also has The same issue.
Arthur Ronald F D Garcia
Tried but with MappedSuperclass I can't create abstract relationships with DrivingLicense.Is there any way of doing a native query retrieving both entities, DrivingLicence and Man, joined?
monit06
@monit06 I see. It makes sense. I will show you how To get your goal by using Native queries
Arthur Ronald F D Garcia
@monit06 Mark The answer as accepted if it fullfil your needs
Arthur Ronald F D Garcia
Doing the native query with this "forced" setter injection works fine!! thanks man!!
monit06