org.hibernate.QueryException: could not resolve property: composite key in query - java

I am trying to fetch the list of records from a view which has a composite primary key with three columns.
I tried to embed the composite key in the entity class. But I am getting the below mentioned errors. The columns of the views (VW_ALERTS) are C_ID, MAT_ID, P_MONTH, CO_TYPE, CO_SUBTYPE.
Here the composite keys are C_ID, MAT_ID, P_MONTH. I am making the property of them in the embeddable class.
Please help to resolve the issue
org.hibernate.QueryException: could not resolve property: coreId of: com.sp.cpem.dto.VwAlerts [FROM com.ct.cpem.dto.VwAlerts d ORDER BY d.cId ASC]
This following code is used to execute the hql.
Session session = sessionFactory.openSession();
String hql = "FROM VwAlerts d ORDER BY d.coId ASC";
Query query = session.createQuery(hql);
return query.list();
The entity class :
#SuppressWarnings("unchecked")
#Entity
#Table(schema = "TIGER", name = "VW_ALERTS")
public class VwAlerts {
#Embedded
private VwAlertsPK vwAlertsPK;
#Basic
#Column(name = "CO_TYPE", nullable = true)
private String coType;
#Basic
#Column(name = "CO_SUBTYPE", nullable = true)
private String coSubType;
Class used to get the composite key
#Embeddable
public class VwAlertsPK implements Serializable {
#Basic
#Column(name = "C_ID", nullable = false)
private BigDecimal cId;
#Basic
#Column(name = "MAT_ID", nullable = true)
private BigDecimal matId;
#Basic
#Column(name = "P_MONTH", nullable = true)
private BigDecimal pMonth;
I am expecting to get all the records from the view.
I tried with the #Id column in the entity class, it failed by returning only the duplicate records of the first row from the view.

Your entity VwAlerts has only 3 properties --> vwAlertsPK, coType, coSubType
but in your HQL you are trying to access a property coreId which does not exist in your entity.
FROM com.ct.cpem.dto.VwAlerts d ORDER BY d.coreId ASC
So add the property coreId to your entity or else just update the ORDER BY clause so you are pointing to correct properties of your entity.

Related

Hibernate and Criteria Api generates wrong Join condition

I got following tables. Lets ignore the fact that the relation is done wrong here. I cannot change that.
Each company can have multiple employes and each employe belongs to only one company.
Table: Company
ID
EMPLOYE_ID
10
100
Table: Employe
ID
NAME
100 (Same as EMPLOYE_ID)
John
Now i want to create a relation #OneToMany between Company -> Employe . My entities look as follow
class Company {
#Id
#Column(name = "id", unique = true, nullable = false)
private String id;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "EMPLOYE_ID", referencedColumnName = "ID")
private Set<Employe> employees;
}
No matter if i try to create a uniderectional, or biderection relationship by adding also #ManyToOne on my Employe class, when using Criteria api to select all Company entities and their Employes i always end up with a wrong generated SQL query at the point where it joines the tables. The above relation for example creates following:
FROM company company0
INNER JOIN employe employe0 ON company0.id = employe0.employe_id
I tried several approaches, but i end up almost with the same error. It tries either to access a column which does not exist on the table, or joins wrong columns (e.g. id = id). Or by the following exception
Caused by: org.hibernate.MappingException: Repeated column in mapping
for entity: com.Employe column: id (should be mapped with
insert="false" update="false")"}}
What is a simple approach to create a bidrectional relation with the above table structure?
Note: I finally ended up changing the DB schema. Still, it would be interesting if someone could provide an answer for such a case, even if it is based on a not well formed
The central problem is that the described table structures do not allow a 1:n relationship from Company to Employee. According to the table design (especially the design of PKs) above, a company can only have one employee.
However, if the DB design cannot be changed, the following approach using the JoinColumnOrFormula annotation may lead to partial success.
The #JoinColumnOrFormula annotation is used to customize the join between a child Foreign Key and a parent row Primary Key when we need to take into consideration a column value as well as a #JoinFormula.
See https://docs.jboss.org/hibernate/stable/orm/userguide/html_single/Hibernate_User_Guide.html#associations-JoinColumnOrFormula for details.
More concretely with these Entities
#Entity
#Table(name="t_company")
public class Company {
#Id
#Column(name="id")
private Integer id;
#Column(name="employee_id")
private Integer employeeId;
#OneToMany(mappedBy = "company")
private List<Employee> employees;
// ..
}
#Entity
#Table(name = "t_employee")
public class Employee {
#Id
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumnOrFormula( column =
#JoinColumn(
name = "id",
referencedColumnName = "employee_id",
insertable = false,
updatable = false
)
)
private Company company;
// ..
}
and this custom repository
#Repository
public class EmployeeRepository {
#Autowired
EntityManager entityManager;
List<Employee> findAll() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
Join<Employee, Company> joinCompany = root.join("company");
TypedQuery<Employee> query = entityManager.createQuery(cq);
return query.getResultList();
}
}
you get the following query:
select
employee0_.id as id1_1_,
employee0_.name as name2_1_
from t_employee employee0_
inner join t_company company1_ on employee0_.id=company1_.employee

Representing #EmbeddedId as SQL for H2 database

I am currently working on a Java project with Hibernate entities (more below). In order to test my data access object layers, I am using H2 database to populate an in-memory database and throwing queries at it. Until this point, everything is fine.
However, the problem comes when simulating the #EmbeddedId annotation.
#Entity
#Table(name = "BSCOBJ")
public class BasicObject extends AbstractDomainObject {
#EmbeddedId // This annotation here
private RestrainPK restrain;
#Embeddable
public static class RestrainPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "CODI", nullable = false)
private String coDi;
#Column(name = "COGA", nullable = false)
private String coGa;
#Column(name = "TYOR", nullable = false)
private String tyOr;
public RestrainPK() {
}
... // Getters and setters
}
}
"Simply" creating the table BSCOBJ and populating it gives no value when fetching data (of course, I checked that the request would give result "normally"). How do I represent this nested class in a SQL table creation / value insertion request ? Is that even possible ?
Thanks in advance,
EDIT
As requested, here is some samples about the SQL / Hibernate ran.
Creation request:
CREATE TABLE BSCOBJ (CODI VARCHAR(5) NOT NULL, COGA VARCHAR(5) NOT NULL, TYOR VARCHAR(5) NOT NULL);
Insertion request:
INSERT INTO BSCOBJ (CODI, COGA, TYOR) VALUES
('HELLO', 'MAT', 'REF'),
('BONJ', 'SOME', 'DAIL'),
('SOPA', 'KDA', 'RATIO');
Request given by Hibernate when trying to run the test code:
select r.restrain.tyOr from mypackage.BasicObject r where r.restrain.coDi = :coDi and r.restrain.coGa = :coGa
With the following values:
coDi = "BONJ";
coGa = "SOME";
Throws a NoResultException. I am expecting DAIL, from the second line of the INSERT request.
I have used #EmbeddedId only one time, but I think that you need #AttributeOverrides under your #EmbeddedId
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "idpk", column = #Column(name="IDPK", nullable = false),
#AttributeOverride(name = "code", column = #Column(name="CODE")
})
and remove your #Column annotations from FormulePK

org.hibernate.QueryException: could not resolve property: createdDate_MOD of: org.baeldung.HibernateAuditDemo.model.Order_AUD

I use hibernate envers for auditing.
I have simple Order entity:
#Entity
#Table(name = "orders")
#Audited
public class Order {
#Id
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
private Long id;
private Double price;
#Temporal(TemporalType.TIMESTAMP)
private Calendar createdDate;
public Order() {
}
//the rest is unimportant
I use AuditorReader to query for revisions at which property has changed:
AuditReader auditReader = AuditReaderFactory.get(entityManager);
// find revision at which order entity changed its property createdDate
List revisions = auditReader.createQuery().forRevisionsOfEntity(Order.class, false, true).
add(AuditEntity.property("createdDate").hasChanged()).getResultList();
Object[] history = (Object[]) revisions.get(0);
In this code I get exception:
org.hibernate.QueryException: could not resolve property: createdDate_MOD of: org.baeldung.HibernateAuditDemo.model.Order_AUD [select e__, r from org.baeldung.HibernateAuditDemo.model.Order_AUD e__, org.hibernate.envers.DefaultRevisionEntity r where e__.createdDate_MOD = :_p0 and e__.originalId.REV.id = r.id order by e__.originalId.REV.id asc]
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:83)
at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:77)
at org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:1967)
In database in table orders and orders_aud, I see column named createdDate but not createdDate_MOD.
Why can't property createdDate be resolved?
To tell hibernate envers track changes to certain property you need to set #Audited(withModifiedFlag = true) on that property.
To set it globally for all entities you need to set org.hibernate.envers.global_with_modified_flag to true in hibernate properties.
The Volodymir's answer perfectly explains what one needs to do in order to invoke AuditEntity.property("some_property").hasChanged() method.
However, some may experience the same mysterious exception when not using the hasChanged method - just like me.
For this setup:
#Entity(name = "prnt")
#Audited
public class ParentClass {
#Id private Long id;
}
#Entity(name = "chld")
#Audited
public class ChildClass {
#Id private Long id;
#ManyToOne #JoinColumn(name = "shrt_prnt_id")
private ParentClass looongishLinkToParentClass;
}
...one may expect this to work:
AuditQuery q = ...;
q.add(AuditEntity.property("shrt_prnt_id")).eq(value));
..or, at least, this:
q.add(AuditEntity.property("looongishLinkToParentClass")).eq(value));
Neither of these do work!
This one does:
q.add(AuditEntity.property("looongishLinkToParentClass_id")).eq(value));

Hibernate Criteria select using embedded object (tuple)

In my case I have a SQL query which looks like:
select * from event_instance where (object_id, object_type) in
(<LIST OF TUPLES RETRIEVED FROM SUBQUERY>);
I want to map this on Hibernate Entities and I have a problem with this query. My mapping looks like that:
#Entity
#Table(name="event_instance")
public class AuditEvent {
<OTHER_FIELDS>
#Column( name = "object_type", nullable = false)
private String objectType;
#Column( name ="object_id" , nullable = false)
private Integer objectId;
}
and second entity:
#Entity
#Table(schema = "els" ,name = "acg_objects")
public class AcgObject implements Serializable{
#Id
#Column(name = "acg_id")
private String acgId;
#Id
#Column(name="object_type")
private String objectType;
#Id
#Column(name="object_id")
private Integer objectId;
<OTHER FIELDS>
}
I already run query for getting AcgObjects and for my DAO I'm getting List only thing I want to do is query a touple using criteria like:
crit.add(Restrictions.in("objectType,objectId",<List of tuples>);
Is it possible? I was trying to use #Embedded object but don't know how exactly construct a query for it. Please help
You can do that not in standard SQL nor using criteria; you have to split in two distinct restrictions or using a Session.SQLQuery() if you want to use specific RDBMS (look at SQL WHERE.. IN clause multiple columns for an explanation)

Error criteria.list using key composite

Entity
#javax.persistence.Entity
#javax.persistence.Table(name = "entidade")
public class Entidade {
private static final long serialVersionUID = -6831078183847196839L;
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "id_titulo", column = #Column(name = "titulo_id", nullable = false)),
#AttributeOverride(name = "id_empresa", column = #Column(name = "empresa_id", nullable = false)) })
private PK pk;
//getter//setter
}
//PK
#Embeddable
public class PK implements Serializable {
private static final long serialVersionUID = -5441836698300495848L;
#javax.persistence.Column(name = "id_titulo")
private Long titulo_id;
#javax.persistence.Column(name = "id_empresa")
private Long empresa_id;
//getter // setter
}
Query is OK : if instance pk setter
Criteria criteria = novoCriteria();
criteria.createAlias("id", "id");
TituloPK pk = new TituloPK();
pk.setEmpresa(2L);
pk.setTitulo(6364L);
criteria.add(Restrictions.eq("id", pk));
criteria.list();
Query error
Criteria criteria = novoCriteria();
criteria.createAlias("id", "id");
criteria.add(Restrictions.eq("id.id_empresa", 2L));
criteria.list();
Error in console : *could not resolve property: id_empresa of: Entidade*
need only search by company, and if I use the constraint returns the above error.
In Criteria, as you know, you must use the name of the member of the class, not the name of the field in your database. But the #AttributeOverride annotation is not overriding this attribute in the PK class, but only in the Entidade class. So you must use the name of the attribute as it is declared in your PK class, that is id.empresa_id.
So your code should be:
Criteria criteria = novoCriteria();
criteria.createAlias("id", "id");
criteria.add(Restrictions.eq("id.empresa_id", 2L));
criteria.list();
In one of my project, I could reproduce your error and could solve it using the name of the parameter in the embeddable class. I think it should work for you as well.

Categories