Representing #EmbeddedId as SQL for H2 database - java

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

Related

Implementing complex MAX function in Spring Boot/JPA query language

Spring Boot here using JPA/Hibernate and CrudRepository impls for managing persistence to my DB tables.
I have the following MySQL table:
CREATE TABLE IF NOT EXISTS price_scarcity_configs (
price_scarcity_config_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
price_scarcity_config_ref_id VARCHAR(36) NOT NULL,
price_scarcity_config_version BIGINT NOT NULL,
price_scarcity_config_updated_on DATETIME NOT NULL,
price_scarcity_config_fizz INTEGER NOT NULL,
CONSTRAINT pk_price_scarcity_configs PRIMARY KEY (price_scarcity_config_id),
CONSTRAINT uc_price_scarcity_configs_ref_id_and_version UNIQUE (price_scarcity_config_ref_id, price_scarcity_config_version)
);
These records will be versioned and different versions of the "same" record will all share the same price_scarcity_config_ref_id. Hence 2+ records can have the same price_scarcity_config_ref_id but will have two distinct different versions.
I'm also using the following JPA/Hibernate entity to model it:
// Uses Lombok annotations to generate getters/setters, etc.
#MappedSuperclass
#Data
#EqualsAndHashCode(callSuper=false)
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String refId;
}
#Entity
#Table(name = "price_scarcity_configs")
#AttributeOverrides({
#AttributeOverride(name = "id", column = #Column(name = "price_scarcity_config_id")),
#AttributeOverride(name = "refId", column = #Column(name = "price_scarcity_config_ref_id"))
})
#Data
#EqualsAndHashCode(callSuper=false)
public class PriceScarcityConfiguration extends BaseEntity {
#Column(name = "price_scarcity_config_version")
private Long version;
#Column(name = "price_scarcity_config_updated_on")
private Date updatedOn;
#Column(name = "price_scarcity_config_fizz")
private Integer fizz;
}
I am now trying to write the PriceScarcityConfigurationRepository and need a fairly sophisticated query. Given a refId, I need to find the record who matches that ref id and has the highest/max version number. The raw SQL query to perform this is:
select
*
from
price_scarcity_configs pcs
inner join
(
SELECT
price_scarcity_config_ref_id,
MAX(price_scarcity_config_version) as max_ver
FROM
price_scarcity_configs
group by
price_scarcity_config_ref_id
) t
on
t.price_scarcity_config_ref_id = pcs.price_scarcity_config_ref_id
and
t.max_ver = pcs.price_scarcity_config_version;
Given my repository and using JPA/Hibernate's built-in query language/annos, how do I implement this query?
public interface PriceScarcityConfigurationRepository extends CrudRepository<PriceScarcityConfiguration,Long> {
#Query("FROM PriceScarcityConfiguration WHERE ??? HOW TO IMPLEMENT THE ABOVE QUERY HERE ???")
PriceSheetConfiguration fetchLatestVersionByRefId(#Param("refId") String refId);
}
You could use the following query instead and use setMaxResults(1)
FROM PriceScarcityConfiguration p WHERE p.refId = :refId ORDER BY p.version DESC
Or simply use the Spring Data notation
List<PriceSheetConfiguration> findFirstByRefIdOrderByVersionDesc(String refId);

Hibernate - AttributeOverride default value when using Embedded

How to override #Column columnDefinition in case of using #Embedded in Hibernate?
To be more specific there is an example:
#Embedded
#AttributeOverrides({ #AttributeOverride(name = "isnettogross", column = #Column(name = "isnettogross", columnDefinition="char(1) default 1", nullable = false))})
public ParentGrossNetTransformVariables grossNetTransform;
and class ParentGrossNetTransformVariables:
#Embeddable
public class ParentGrossNetTransformVariables {
#Column(name = "isnettogross", columnDefinition="char(1) default 0", nullable = false)
public boolean isNet2GrossTransform;
as i use:
lConf.setProperty("hibernate.hbm2ddl.auto", "update");
the changes in database are applied automaticly. Now I need to add ParentGrossNetTransformVariables in multiple entities but with different default value of "isnettogross" so that I try to use #AttributeOverrides but it doesnt work. Is there any way to do it ?
I am assuming "it doesn't work" as the changes made to column names not being reflected in the database.
hbm2ddl.auto=update does not update the schema. So changes you make to the column names does not get reflected in the database.
Change it to create so that it re-creates the schema based on the changes made, if any.
UPDATE:
Use insertable=false attribute along with the columnDefintion in your embeddable class, i.e.
#Column(name = "isnettogross", columnDefinition="char(1) default 0", nullable = false, insertable=false)
and the entity class,
#AttributeOverrides({ #AttributeOverride(name = "isnettogross", column = #Column(name = "isnettogross", columnDefinition="char(1) default 1", nullable = false, insertable=false))})
This ignores the column of interest in the INSERT statement that is fired, thereby inserting the default value configured.
The same goes for updatable, so you might wanna use that too based on your use case.
LATEST:
I'm quite puzzled as to how it isn't working in your code. I have tried and tested; and it's working fine.
I have attached the code too just in case you wanna have a look and cross verify.
#Entity
public class Demo {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Embedded
#AttributeOverride(name="flag", column=#Column(name="MainFlag", columnDefinition="char(1) default 1", insertable=false))
private Misc misc;
private Misc misc2;
// Getters and setters
#Embeddable
public class Misc {
#Column(name="flag", columnDefinition="char(1) default 0", insertable=false)
private boolean flag;
// Getters and setters
The code to test is a simple session.save() which generated the query
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into Demo (id) values (?)
Attaching the values persisted in the database as well :D

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: 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.

Hibernation annotations, specify column default value

I have a domain object and annotated as follows
#Entity
#Table(name = "REQUEST")
public class Request {
/**
* Unique id for this request
*/
#Id
#GeneratedValue
#Column(name = "EQ_ID")
private long requestId;
/**
*
*/
#Column(name = "EMAIL_ID")
private String emailId;
/**
*
*/
#Column(name = "REQUEST_DATE")
private Date requestDate;
/**
*Getters/setters omitted
*/
}
The column Request_date cannot be null and as per the DDL the default value is sysdate (oracle DB). How do I annotate this field so that if the requestDate property is null,hiberanate automatically inserts sysdate.? Currently it throws error when the field is null,which is very obvious as it cannot be null as per the DB constraints. How do I go about this?
One alternative is to mark this field as transient and the inserts work fine. But the negative aspect is that, I will not be able to retrieve the value (of request_date column).
This is a missing feature in hibernate annotations. Also there exist some workaround as Yok has posted. The problem is that the workaround is vendor dependent and might not work for all DB. In my case,Oracle, it isn't working and has been reported as a bug.
You can put the default value in a columnDefinition. An example would look like:
#Column(name = "REQUEST_DATE", nullable = false, columnDefinition = "date default sysdate")
Using #ColumnDefault (Work for DDL update).
hibernate.hbm2ddl.auto=update
import org.hibernate.annotations.ColumnDefault;
....
#ColumnDefault(value="'#'")
#Column(name = "TEMP_COLUMN", nullable = false)
public String getTempColumn() {
return tempColumn;
}
DDL Generate:
Alter Table YOUR_TABLE add TEMP_COLUMN varchar2(255) default '#' not null;
Assign a default value to the field:
private Date requestDate = new Date();
If you mark your entity with #DynamicInsert e.g.
#Entity
#DynamicInsert
#Table(name = "TABLE_NAME")
public class ClassName implements Serializable {
Hibernate will generate SQL without null values. Then the database will insert its own default value. This does have performance implications See Dynamic Insert.
Make the default in Oracle for the column SYSDATE:
ALTER TABLE APP MODIFY (REQUEST_DATE DEFAULT SYSDATE);
Then, from Hibernate's perspective it can be nullable.
Hibernate will save a NULL to the database. Oracle will convert that to SYSDATE. And everyone will be happy.
I resolved assigning a value to the variable like this private Integer active= 0;
#Entity
#Table(name="products")
public class ServiziTipologia {
#Id
#GeneratedValue
private Integer id;
private String product;
private String description;
private Integer active= 0;

Categories