In our project we have different user types presented by different classes. And we have a BaseEntity class as @MappedSuperclass. When we try to use user classes with InheritanceType.JOINED hibernate creates an sql that we think it is wrong.
Base Entity :
@MappedSuperclass
public abstract class BaseEntity implements java.io.Serializable {
private Integer id;
private Date createdDate = new Date();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "CREATED_DATE", nullable = true)
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
}
Base User
@Entity
@Table(name = "BASE_USER")
@Inheritance(strategy = InheritanceType.JOINED)
@AttributeOverride(name = "id", column = @Column(name = "ID", nullable = false, insertable = false, updatable = false))
public abstract class BaseUser extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
@SequenceGenerator(name = "seq", sequenceName = "USER_SEQ", allocationSize = 1)
public Integer getId() {
return super.getId();
}
}
User
@Entity
@Table(name = "FIRM_USER")
public class FirmUser extends BaseUser {
private String name;
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Sample Code
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration()
.addAnnotatedClass(FirmUser.class)
.addAnnotatedClass(BaseUser.class)
.addAnnotatedClass(BaseEntity.class)
.configure()
.buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
}
public static void main(String[] args) {
getSession().save(new FirmUser());
Query query = getSession().createQuery("select distinct a from FirmUser a ORDER BY a.id");
query.list();
}
}
For this hql
select distinct a from FirmUser a ORDER BY a.id
hibernate creates this sql
select distinct firmuser0_.ID as ID1_0_,
firmuser0_1_.CREATED_DATE as CREATED_2_0_,
firmuser0_.name as name1_1_
from FIRM_USER firmuser0_
inner join BASE_USER firmuser0_1_ on firmuser0_.ID=firmuser0_1_.ID
order by firmuser0_1_.ID
"order by firmuser0_1_.ID" causes
HSQLDB : ORDER BY item should be in the SELECT DISTINCT list:
or
ORACLE : ORA-01791: not a SELECTed expression
But firmuser0_.ID is in select clause and we actually try to order by ID of FirmUser (firmuser0_) not BaseUser (firmuser0_1_)
If we do not use BaseEntity it works as expected.
Why does hibernate use joined class for ordering in case of it also inherits from another class?
I replicated your test case, you can find it on GitHub.
There must be a Hibernate bug, because when you use the alias, the select clause uses the subclass ID, while the ORDER BY uses the base class id, which since it's not in the select clause, throws an exception:
SELECT inheritanc0_.id AS ID1_0_,
inheritanc0_1_.created_date AS CREATED_2_0_,
inheritanc0_.NAME AS name1_1_
FROM firm_user inheritanc0_
INNER JOIN base_user inheritanc0_1_
ON inheritanc0_.id = inheritanc0_1_.id
ORDER BY inheritanc0_1_.id
Notice the ORDER BY inheritanc0_1_.id
, it should have been ORDER BY inheritanc0_.id
instead.
Rewrite the query without alias:
List<FirmUser> result1 = (List<FirmUser>) session.createQuery("from FirmUser order by id").list();
The SQL being properly generated:
SELECT inheritanc0_.id AS ID1_0_,
inheritanc0_1_.created_date AS CREATED_2_0_,
inheritanc0_.NAME AS name1_1_
FROM firm_user inheritanc0_
INNER JOIN base_user inheritanc0_1_
ON inheritanc0_.id = inheritanc0_1_.id
ORDER BY inheritanc0_1_.id
or specifying the subclass.id as well, but that results in an array of subclass and subclass entity tuples:
List<Object[]> result2 = (List<Object[]>) session.createQuery("select distinct a, a.id from FirmUser a order by id").list();
Giving the following SQL:
SELECT DISTINCT inheritanc0_1_.id AS col_0_0_,
inheritanc0_1_.id AS col_1_0_,
inheritanc0_.id AS ID1_0_,
inheritanc0_1_.created_date AS CREATED_2_0_,
inheritanc0_.NAME AS name1_1_
FROM firm_user inheritanc0_
INNER JOIN base_user inheritanc0_1_
ON inheritanc0_.id = inheritanc0_1_.id
ORDER BY inheritanc0_1_.id
Like always, a native query gives you the ultimate control over any tuple association:
List<FirmUser> result3 = (List<FirmUser>) session.createSQLQuery(
"select * " +
"from FIRM_USER a " +
"LEFT JOIN BASE_USER b ON a.id = b.id " +
"order by a.id"
)
.addEntity("a", FirmUser.class)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
You should fill a Hibernate issue for this problem, as it's not behaving as it should be.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With