Error criteria.list using key composite - java

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.

Related

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

How to create hibernate composite key and get values from table

I am trying to use hibernate annotations for getting data from a MySQL database table which doesn't have a primary key defined.
However the fact is 2 columns of that table together are unique in the table. How can I achieve the same using hibernate annotation?
This is my code
#Entity
#Table(name = "coc_order_view")
public class CoCOrderDetailsTest {
#EmbeddedId
private MyJoinClassKey key;
#Column(name = "coupon_code")
private String couponCode;
some other columns and their getters and setters .....
#Embeddable
public class MyJoinClassKey implements Serializable {
private static final long serialVersionUID = -5L;
#Column(name = "product_id")
private int productId;
#Column(name = "order_id")
private int orderId;
gettes and setters....
And here is my criteria query
Criteria criteria = getHibernatetemplate().getSession().createCriteria(CoCOrderDetailsTest.class);
criteria.add(Restrictions.eq("status", "New"));
ArrayList<CoCOrderDetailsTest> orderDet = (ArrayList<CoCOrderDetailsTest>) getHibernatetemplate().get(criteria);
I am unable to get all the values from db. Kindly suggest some solutions.
After reading through your question again not sure this will help. You can't have a table without primary key(s). Read the first couple of paragraphs in this article
That said, if you can alter the table and add primary keys on those fields you need to add #IdClass annotation to your class signature for CoCOrderDetailsTest and then get rid of the #embeddable and #embeddedId notation in your classes.
Another alternative, if you can add a field to the table, would be to use an #GeneratedValue on that added primary key field and of course annotate it with #Id.
If you can't alter the table then you can't use JPA and you'll have to use JDBC.
See http://docs.oracle.com/javaee/5/api/javax/persistence/IdClass.html
A working example:
#Entity
#Table(name = "player_game_log")
#IdClass(PlayerGameLogId.class)
public class PlayerGameLog {
#Id
#Column(name = "PLAYER_ID")
private Integer playerId;
#Id
#Column(name = "GAME_ID")
private String gameId;
....
and the id class (note there are no annotations on the id class)....
public class PlayerGameLogId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer playerId;
private String gameId;
Try:
String hql = "FROM CoCOrderDetailsTest WHERE status = :status";
Query query = session.createQuery(hql);
query.setParameter("status","New");
List results = query.list();
I usually use EntityManager rather than session so I'm not familiar with this syntax - and I have typically added a type to the list to be returned - like:
List<CoCOrderDetailsTest> results = query.list();

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));

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

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.

How set where in templates using jpa in CriteriaQuery

I am beginner in java EE and I need know, how set a clausule where in this code of criteria
public <T> List<T> findEntity(Class<T> entityClass) {
CriteriaQuery<T> criteria = builder.createQuery(entityClass);
Root<T> entityRoot = criteria.from(entityClass);
criteria.select(entityRoot);
criteria.orderBy(order);
return em.createQuery(criteria).getResultList();
}
They will notice that I am using templates in java (<T>) to make this code work with various entities from my database.
Then I pass the sql (in postgresql) code and the entity class.
SQL:
CREATE TABLE activity
(
id integer NOT NULL,
name text NOT NULL,
_modified timestamp without time zone,
_user integer,
_enable boolean,
)
And class entity
public class activity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "activity_id_activity_seq" )
#SequenceGenerator( name = "actividad_id_actividad_seq", sequenceName = "actividad_id_actividad_seq", allocationSize = 1, initialValue = 110 )
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "_modified")
#Temporal(TemporalType.TIMESTAMP)
private Date modified;
#Column(name = "_enable")
private Boolean enable;
#Column(name = "_user")
private Integer user;
.......
}
I need to know is how to add a where clause in the code of the function findEntity using methods template.
The where clause of criteria should be matching the column _Enable, this column this column mentioned is repeated in 4 tables in my database, so you note that it is better to reuse code in that function.
thanks
Here is an example how to add where() clause:
public static <T> List<T> findEntity(Class<T> entityClass, boolean isEnabled) {
CriteriaQuery<T> criteria = builder.createQuery(entityClass);
Root<T> entityRoot = criteria.from(entityClass);
criteria.select(entityRoot);
criteria.where(builder.equal(
entityRoot.get("enable"), //path expression
builder.parameter(Boolean.class, "isEnabled")) //parameter expression
);
criteria.orderBy(order);
return em.createQuery(criteria)
.setParameter("isEnabled", isEnabled)
.getResultList();
}
The entityRoot.get("enable") statement defines Path<String> expression. This is equivalent of a.enable which uses a colon to denote a parameter in JPQL, i.e.
SELECT a FROM Activity a WHERE a.enable = :isEnabled
To build conditional expression one must also create a ParameterExpression<Boolean> which corresponds to the parameter of typed query that executes our criteria.
Using this approach you can easily extend your generic method with new parameters.
I hope it helps.

Categories