java - relacion - mapeo one to one hibernate
Hibernate utiliza un nombre de tabla incorrecto para orden por expresión con herencia de tres niveles (1)
En nuestro proyecto tenemos diferentes tipos de usuarios presentados por diferentes clases. Y tenemos una clase BaseEntity como @MappedSuperclass. Cuando intentamos usar clases de usuario con InheritanceType.JOINED, hibernate crea un sql que creemos que está mal.
Entidad Base:
@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;
}
}
Usuario base
@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();
}
}
Usuario
@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;
}
}
Código de muestra
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();
}
}
Para este hql
select distinct a from FirmUser a ORDER BY a.id
hibernate crea este 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
"orden por firmuser0_1_.ID" causas
HSQLDB : ORDER BY item should be in the SELECT DISTINCT list:
o
ORACLE : ORA-01791: not a SELECTed expression
Pero firmuser0_.ID está en la cláusula de selección y en realidad intentamos ordenar por ID de FirmUser (firmuser0_) no BaseUser (firmuser0_1_)
Si no usamos BaseEntity, funciona como se espera.
¿Por qué hibernate usa la clase unida para ordenar en caso de que también se hereda de otra clase?
Repliqué tu caso de prueba, puedes encontrarlo en GitHub .
Debe haber un error de Hibernate, porque cuando se usa el alias, la cláusula de selección usa el ID de subclase, mientras que ORDER BY usa el ID de clase base, que como no está en la cláusula de selección, lanza una excepción:
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
Observe que ORDER BY inheritanc0_1_.id
, debería haber sido ORDER BY inheritanc0_.id
lugar.
Solución 1:
Reescriba la consulta sin alias:
List<FirmUser> result1 = (List<FirmUser>) session.createQuery("from FirmUser order by id").list();
El SQL se genera correctamente:
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
Solución 2:
o especificando también la subclase.id, pero eso da lugar a una matriz de tuplas de subclase y entidad de subclase:
List<Object[]> result2 = (List<Object[]>) session.createQuery("select distinct a, a.id from FirmUser a order by id").list();
Dando el siguiente 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
Solución 3:
Como siempre, una consulta nativa le da el control definitivo sobre cualquier asociación de tupla:
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();
Debería llenar un problema de Hibernate para este problema, ya que no se comporta como debería.