Inserting a ZonedDateTime value to Oracle Timestamp With Timezone Column With JPA - oracle

In my SpringBoot project, I am trying to insert a ZonedDateTime value to an Oracle database where the column type is specified as TIMESTAMP WITH TIMEZONE. When I do that, the inserted value gets converted to the JVM timezone and gets inserted. However, what I expect is to insert the value in ZonedDateTime property as it is.
For example, if the ZonedDateTime value is set to 2020-05-16T12:12:24+02:30[US/Denver], then I expect to write to DB the same value and read from DB the same value. Is there any way I can do this with Hibernate and JPA
#Entity
class MyEntity{
ZonedDateTime myDateTimeWithTimeZone;
}
#Repository
public interface MyRepository extends JpaRepository<MyEntity, Long>
{
}
This is how i am going to use it,
MyEntity myEntity = new MyEntity();
myEntity.setMyDateTimeWithTimeZone(ZoneDateTime.now('US/Denver')) // This timezone can be anything depending on userInput
myRepository.save(myEntity);

Related

How to make #Indexed as unique property for Redis model using Spring JPA Repository?

I have a model class that I store in Redis and I use Jpa Repository with Spring java. Normally(not with redis) jpa repository is saving the new data or updates(conditionally) if the given model is already exist in Db. Here, I want to add new item to redis but if it is not already exists on db otherwise update it just like usual Jpa implementation.
Here is my model:
#Getter
#Setter
#RedisHash("MyRecord")
public class MyRecordRedisModel {
private String id;
#Id
#Indexed
private String recordName;
private Date startDate;
private Date endDate;
}
And my repository class is just a normal spring jpa repo as follows:
#Repository
public interface IFRecordRedisRepository extends JpaRepository<IFRecordRedisModel, String> {
Page<IFRecordRedisModel> findAll(Pageable pageable);
}
Unique key must be the name (I totally do not care about uniquiness of the id). Thus, if the name is already exist in Db than do not add it again. I marked it as Indexed but still it is adding same data (with same recordName).
How can I make it unique?
This would require an additional query, but I think this solution would work for you. You can use query by Example to check if there exists a record with that name, and save conditionally, or do something else if it already exists.
IFRecordRedisModel exampleRecord = new IFRecordRedisModel();
exampleRecord.setRecordName(inputRecord.getRecordName());
if (!repository.exists(Example.of(exampleModel)))
repository.save(inputRecord);
else ..... // do something else

Is there simple way of changing timezone between dto and entities at database?

I write application on Spring Boot with Spring Data(postgresql).
I have the following case. I want to store in database time at UTC timezone, and parse it to/from "America/San-Paulo" timezone in dto.
For example: in controller I get dto with LocalDateTime in America/San-Paulo timezone. And I want to save it in database in UTC timezone.
I can do in when mapping from dto to entity. But maybe there is another simple way like setting some properties of hibernate/spring?
Since Java 8, we have the Date/Time API under java.time!
(1) Convert the timezone in annotated #PrePersist, #PreUpdate, and #PostLoad methods.
For example, in annotated #PostLoad, convert from UTC to America/San-Paulo.
private static ZoneId UTC_ZONE = ZoneId.of("UTC");
private static ZoneId LOCAL_ZONE = ZoneId.of("America/San_Paulo");
private LocalDateTime dateTime;
#PostLoad
public void toLocal() {
dateTime = dateTime.atZone(UTC_ZONE).withZoneSameInstant(LOCAL_ZONE).toLocalDateTime();
}
(2) Assuming you are using Jackson, you can write a custom serializer/deserializer.
UPDATE:
With PostgreSQL, you can use the type timestamp with time zone. By default, if you insert/update the column, it will convert the value to UTC.
In JPA:
#Column(columnDefinition = "timestamp with time zone")
UPDATE (22-07-01):
You could also use an AttributeConverter.

Spring JPA Equal conditon with derived query for LocalDate not working

I have a Oracle DB with type of DATE my Entiy class have LocalDate parameter as shown in here
#Entity
#Table(name = "CONTRACT")
public class ContractEntity {
private Long id;
private LocalDate contractStartDate;
private LocalDate contractEndDate;
...
For the testing I created derived query to find Entity by contractStartDate
public interface ContractRepository extends JpaRepository<ContractEntity, Long>, JpaSpecificationExecutor<ContractEntity> {
ContractEntity getContractEntityByContractStartDateIs(LocalDate date)
}
Then I created Two Tests as follows;
#DisplayName("Should get Exact Date Entity")
#Test
void test1(){
LocalDate date=LocalDate.of(2021,03,9);
ContractEntity entity= searchService.getByDate(date); // getByDate is mapped to getContractEntityByContractStartDateIs() in service layer
assertEquals(date,entity.getContractStartDate());
}
#DisplayName("Should match ID:1 Entity's Date with Local Date")
#Test
void test2(){
ContractEntity entity=searchService.getById(1l).get();
assertEquals(1l,entity.getId());
LocalDate date=LocalDate.of(2021,03,9);
assertEquals(date,entity.getContractStartDate());
}
}
My problem is test1 fails with null error which means equality condition fails to give existence of that Entity even though test2 passed which date is equal to id:1 entity's Start-date
p.s: I have set Contract Table's ID:1 Contract Start Date value to 2021,03,9 as shown in image here
So what would be the reason for this Why test1 fails to get equal entity and why test2 pass that assert equity of date is true
LocalDate doesn't contain a time component, but the data type you used in the database does and it is not 0 for the data in the database.
In order to make the comparison (which happens in the database) the LocalDate gets converted with a date + time where the time is probably 0, which is not equal to the date+times present in the database.
When the entity gets loaded the time part of the database value gets dropped and the result is equal to your LocalDate value.

spring boot - calculated field

So, I have an entity, that has field start_date (java.util.Date is the type).
I want to have another field, that would automatically populate with integer that corresponds to day of week (as a number 1 for sunday, 2 for monday, etc.) of starting date.
Here's fragment of my entity:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#DateTimeFormat(pattern = "yyyy-MM-dd")
#Temporal(TemporalType.DATE)
private Date start_date;
I've tried to add the calculated field in the following way:
#Column(name = "weekday")
#Formula("(select dayofweek(l.start_date) from Lesson l where l.id = id)")
private Integer weekDay;
However, when looking at the Lesson table in H2 console, there's no such column as "weekday"
I also tried other option - without #Formula annotation and with a setter that takes start_date parameter, but I guess this setter is never called, since the column "weekday" is populated with null.
Here's the setter I've tried to use as an alternative solution:
public void setWeekDay(Date start_date) {
Calendar c = Calendar.getInstance();
c.setTime(start_date);
this.weekDay = c.get(Calendar.DAY_OF_WEEK);
}
It's obvious that I'm missing something here, it's probably because I'm still learning Spring boot...
To sum up - I want to have a column in table Lesson, that is calculated from another column of the same table.
#Formula means your field to be calculated by your rules. This entity field is not column in db. This field is calculating for each entity in loading time by specified rule.
If annotation #Column(name = "weekday") would work near #Formula you would be really confused if you expect in loaded entity same value as in DB but here is calculated one and different (inconsistent situation).
If you want save here value from the Lesson table you should remove #Formula and use #EntityListeners({YourEntityJpaCallbacksListener.class}) In spring bean YourEntityJpaCallbacksListener you can define methods marked with #PreUpdate or #PrePersist and use correspond operations to set calculated value into weekday.
for example:
#EntityListeners({YourEntityJpaCallbacksListener.class})
#Entity
public class YourEntity{
// your code
}
#Component
public class YourEntityJpaCallbacksListener {
#Autowired
private LessonRepository lessonRepository;
#PreUpdate
void preUpdate(YourEntity yourEntity) {
if (recurrentRuleRepository.exists(yourEntity.getId())) {
Integer weekDay = lessonRepository.findOne(yourEntity.getId());
yourEntity.setWeekDay(weekDay);
}
}
}
Ok, so I think I have managed to solve this.
I have removed the #Formula annotation
I have created a method that calculates the day of the week and writes it to weekDay.
public void calculateDayOfWeek(){
Calendar c = Calendar.getInstance();
c.setTime(start_date);
this.weekDay = c.get(Calendar.DAY_OF_WEEK);
}
And I put it inside start_date setter:
public void setStart_date(Date start_date) {
this.start_date = start_date;
calculateDayOfWeek();
}
So now, evertime the start_date is created or updated, it updates (or creates) the value of weekDay.

How to store Joda DateTime in MySQL

I've recently started using Joda time library for my test project.
Particularly i have been enjoying the capabilities of DateTime and functions for its manipulation.
My query is how do you store DateTime in MySql. I am using Spring & Hibernate for my application.
my current entity throws deserialisation errors whenever I try and use it:
#Entity
#Table(name = "test_storage")
public class TestEntity {
#Id #GeneratedValue
private int id;
#Column
private DateTime testDate;
//getters and setters
}
The mysql table structure is as follows:
Name: test_storage
Columns:
id INT NOT_NULL, AUTO_INCREMENT
testDate DATETIME
Any advice?
If you are using Hibernate 4+, then you can adopt the Jadira user types which allow you to map DateTime (and other JODA date time related class like LocalDate, LocalDateTime etc) to DB fields using different strategies.
Your mapping will look like
public class TestEntity {
//...
#Column
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime testDate;
}
Read the documents to know how to properly use these types to fit your requirements.
The biggest pitfall that you may face soon is, as Java's Date does not include timezone information nor does it sticks to UTC (JODA's user types still need to map to Timestamp/Date internally), you may want to make sure the way you store does provide proper information. For example, either store the date time as UTC, or store timezone information as a separate field, etc.
DATETIME would be my choice. See some more details at What difference between the DATE, TIME, DATETIME, and TIMESTAMP Types and http://infopotato.com/blog/index/datetime_vs_timestamp

Resources