Hibernate expecting Date for Timestamp database column - java

I am using projections to retrieve a subset of columns into a DTO. Below is the DTO
QuestionPreviewDto.java
private Long id;
private String question;
private Timestamp datePosted;
public QuestionPreviewDto(Long id, String question, Timestamp datePosted){
this.id = id;
this.question = question;
this.datePosted = datePosted;
}
Database table
CREATE TABLE question
(
id BIGINT NOT NULL,
question varchar(250) NOT NULL,
date_posted TIMESTAMP,
.....
)
Below is the repository method to populate the DTO where QuestionEntity is the entity class mapped to the database table question.
#Query("select new QuestionPreviewDto(id, question, datePosted) from QuestionEntity where id = :id")
QuestionPreviewDto getQuestionPreview(#Param("id") Long id);
The query above give me the following error
Unable to locate appropriate constructor on class [QuestionPreviewDto]. Expected arguments are: long, java.lang.String, java.util.Date
[cause=org.hibernate.PropertyNotFoundException: no appropriate constructor in class: QuestionPreviewDto]
Not sure why Hibernate is expecting java.util.Date when type for datePosted is Timestamp in database and Java class ?

Inside the DTO you can use Date only with Temporal as Timestamp like below
#Temporal(TemporalType.TIMESTAMP)
private java.util.Date utilTimestamp;
While you save it in Date in DTO it will automatically converted in to timestamp its a timestamp in DB.

Make sure that your QuestionEntity
mapped properly according to O\R mapping documentation:
date, time, timestamp
Type mappings from java.util.Date and its subclasses to SQL types DATE, TIME and TIMESTAMP (or equivalent).
calendar, calendar_date
Type mappings from java.util.Calendar to SQL types TIMESTAMP and DATE (or equivalent).
https://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-types-entitiesvalues

I had the same problem with my quarkus application using hibernate.
I solved it by changing the field in my DTO to Date and annotate it like this:
#Type(type="timestamp")
private Date datePosted;
This did not change the format of the timestamp, and my Entity class could still use the Timestamp type like this:
#Type(type="timestamp")
private Timestamp datePosted;
So apparently this workaround is only needed for DTO projection.

Related

Spring JPA automatically fetch system time stamp from database

I'd like to fetch the current system timestamp: SELECT CURRENT_TIMESTAMP; automatically every time I run a select operation.
Sample code below:
SomeEntity.java
#Entity
#Table(name = "some_table")
public class SomeEntity {
#Column(name = "name", length = 500)
private String name;
#Column(name = "current_timestamp")
private LocalDate currentTimestamp;
}
The currentTimestamp column is not physically present in the table but I wish to get the CURRENT_TIMESTAMP value from the database to be populated in this field every time I perform a SELECT operation as below:
List<SomeEntity> records = someCrudRepository.findByName("someName")
OR List<SomeEntity> records = someCrudRepository.findAll()
In short, I'd like to run this query via Spring JPA: SELECT name, current_timestamp FROM some_table;
Is there any way to achieve the same except using native or jpql queries?
I don't want to use Java time library for getting the timestamp as that is not the overall purpose of getting the current timestamp.
Hibernate's #Formula is what you are looking for:
import org.hibernate.annotations.Formula;
public class SomeEntity {
...
#Formula("current_timestamp")
private LocalDate currentTimestamp;
}

Exclude some fields from audit with Spring Data JPA #LastModifiedDate

I have an entity called User. This entity contains several fields and one of them is lastModifiedDate:
#LastModifiedDate
#Column(name = "last_modified_date", columnDefinition = "DATETIME")
private ZonedDateTime lastModifiedDate;
Every time the table is updated, this field gets updated too. Which per se is fine.
The issue is that in the same entity I have also another field called loginTime:
#Column(name = "login_time", columnDefinition = "DATETIME")
private ZonedDateTime loginTime;
This field is updated whenever a new user logs into the application.
However, when users log in, since the loginTime field is updated, the field lastModifiedDate is also updated consequently.
Is there a way to prevent lastModifiedDate from being updated when specific fields (like loginTime) are updated?
Thank you
You can use JPQL update query using #Query to update only loginTime field then lastModifiedDate field will not be updated.
#Modifying
#Query("update User u set u.loginTime = :loginTime where u.id = :id")
int updateLoginTime(#Param("loginTime") ZonedDateTime loginTime, #Param("id") Integer id);

Select data with ZonedDateTime

I have object
...
#CreatedDate
#Column(name = "created_date", nullable = false)
#JsonIgnore
private ZonedDateTime createdDate = ZonedDateTime.now();
...
table - postgeSQL
create table inventory_request
(...
created_date timestamp,
.....
);
I need to select objects with databases between dates ZonedDateTime.now() and last year - ZonedDateTime.now().minusMonths(12)
my JPA repository
List<Inventory> findByCreatedDateBetween(ZonedDateTime now, ZonedDateTime end);
after execute i have only empty array, but values is present in database
I try use TimeStamp - 'java.lang.IllegalArgumentException: Parameter value [2018-11-20 14:44:23.528] did not match expected type [java.time.ZonedDateTime (n/a)]'
How is fix it? How to get the necessary data please help? Thanks!

Persistence entity with two Date fields, and both are changed on update, how?

I'm having problems where two Date fields are updated to the exact same date when only one should be. I'm trying to figure out why this is happening and how I can update only the one date field I want updated, and leave the other at its original value.
I'm using Hibernate with JPA on a MySQL database, in case that is part of the reason.
I have a persistence entity that looks something like this:
#NamedQueries({
#NamedQuery(name="MyObject.updateItem", query="UPDATE MyObject m SET m.item = :item, m.lastUpdate = :updated WHERE m.id = :id")
})
#Entity
#Table(name="entries")
public class MyObject implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String item;
#Column(columnDefinition = "TIMESTAMP", nullable = false)
private Date dateCreated = new Date();
#Column(columnDefinition = "TIMESTAMP", nullable = false)
private Date lastUpdate = new Date();
// after here standard constructors, getters, setters, etc.
}
When from my DAO I call the NamedQuery and provide the correct paramters, I find that both lastUpdate and dateCreated are changed. Is there any reason for this and how can I prevent this from happening? Is this caused because I initialize the to date fields in the entity class?
I'm using the TIMESTAMP column definition because I want to be able to perform queries with < or >.
lastUpdate and dataCreated, aftare update have the same value?
I don't know if this will be a solution for you but this is what I commonly do for all of the entities I regularly implement. Add a PrePersist and PreUpdate function to your entity in order to set the created and last modified times. Also try adding #Temporal(TemporalType.TIMESTAMP) to each of your date fields.
#PrePersist
public void prePersist() {
this.dateCreated = new Date();
this.lastUpdated = this.dateCreated;
}
#PreUpdate
public void preUpdate() {
this.lastUpdated = new Date();
}
Beyond that, I'm a little stumped...
So I figured out the problem wasn't to do with my query or how I used persistence but how I built the database itself.
When I created the table to contain the data for the object I didn't specify a specific default for a NOT NULL field.
My original SQL CREATE statement looked something like this.
CREATE TABLE IF NOT EXISTS `entries` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`item` VARCHAR(255) NOT NULL,
`dateCreated` TIMESTAMP NOT NULL,
`lastUpdate` TIMESTAMP NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
When the MySQL Server executed this statement it deferred the first TIMESTAMP field (in this case dateCreated) with the default to fill it with the CURRENT_TIMESTAMP and the attribute on update CURRENT_TIMESTAMP which was unexpected by me.
I corrected this problem by changing default for the field to DEFAULT '0000-00-00 00:00:00' and by changing my CREATE TABLE statement to force this default so my new statement looks like
CREATE TABLE IF NOT EXISTS `entries` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`item` VARCHAR(255) NOT NULL,
`dateCreated` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastUpdate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This apparently allows me to update the fields that I want without causing the other to update automatically.
I'm still not sure why MySQL assumed the defaults that it did. I guess it's probably somewhere in the documentation.

Hibernate Timestamp to LocalDateTime conversion unexpected result

I've an issue with the conversion of 1000-01-01 00:00:00.0 to a LocalDateTime object. i've already checked the Oracle docs to see if maybe 1000-01-01 isn't supported, but that doesn't seem the problem.
The versions I'm using
hibernate-core: 5.2.1.Final
hibernate-commons-annotations: 5.0.1.Final
hsqldb: 2.3.4
spring-test-dbunit: 1.2.0
This is how startDate looks in MyEntity.class
#Basic
#Column(name = "start_date", nullable = false)
public LocalDateTime getstartDate() {
return startDate;
}
Hibernate creates it like this:
Query:[create table my_table (end_date timestamp not null, start_date timestamp not null)]
I've a (example) dataset with the following row
<my_table startDate="1000-01-01 00:00:00.0" endDate="4000-01-01 00:00:00.0" />
DBUnit is loading the data in an in memory database using Hibernate
Query:["insert into my_table(START_DATE, END_DATE) values (?, ?)"]
Params:[(1=1000-01-01 00:00:00.0,2=4000-01-01 00:00:00.0)]
In my JUnit test I fetch the data using an (Hibernate) Entitymanager and following named query:
#NamedQuery(
name = "MyTable.fetchAll",
query = "FROM MyTable m"
)
The select query (simplified):
Query:["select end_date as date_e12_4_, start_date as date_s13_4_ from my_table mytable0_"]
In my JUnit test I assert the returned result but I get an AssertionError:
java.lang.AssertionError:
Expected :MyEntity{startDate=1000-01-01T00:00, endDate=4000-01-01T00:00}
Actual :MyEntity{startDate=1000-01-05T23:09:21, endDate=4000-01-01T00:00}
My startDate 1000-01-01T00:00 becomes 1000-01-05T23:09:21.
The problem doesn't occur with the endDate.
Has anyone had this issue before? Or does anyone know how to solve it?
Please let me know if you need some more information.
Any help is greatly appreciated.
Update: it works when I use LocalDate instead of LocalDateTime.
For the new type from Java 8, you need another dependency from Hibernate.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>5.0.1.Final</version>
</dependency>
After adding this, use LocalDateTime like normal Basic type.
private LocalDateTime validFrom;
Updated
I try to reproduce your situation.
Here is how i implemented the class.
#Entity
public class MyTable extends ABaseEntity {
private LocalDateTime startDate;
#Type(type="org.hibernate.type.LocalDateTimeType")
public LocalDateTime getStartDate() {
return startDate;
}
public void setStartDate(LocalDateTime startDate) {
this.startDate = startDate;
}
}
Data in database
ID STARTDATE
1 25-AUG-16 12.00.00.000000000 AM
The result when i read back
2016-08-25T00:00
Hope this will help!

Categories

Resources