Is there a #LastAccessedTimestamp in JPA - java

I want to store the last read time in a Date column when ever someone tries to load or fetch(select query, findBy methods) a entity
I had a look at #PostLoad as explained in this site . Have following questions :-
(a)Just want to know if this is safe to Update entity in #PostLoad
(b) Is there something like #LastAcessedTime in JPA similar to #UpdateTimestamp ?
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.time.LocalDate;
#Data
#Entity
public class SensitiveInfo {
#Id
private Long id;
private String data;
#CreationTimestamp
private LocalDate createdDate;
#UpdateTimestamp
private LocalDate updationTimeStamp;
// Is there a JPA automatic way to Update this field any time hibernate loads this entity ?
private LocalDate updationTimeStamp;
}

Related

#Calculation annotation does not work in OpenXava

In my OpenXava application, the #Calculation annotation does not work.
Here my coding for my #Embeddable that uses #Calculation:
import java.math.*;
import java.time.*;
import javax.persistence.*;
import org.openxava.annotations.*;
import lombok.*;
#Getter #Setter
#Embeddable
public class Payment {
#ManyToOne(fetch=FetchType.EAGER)
#DescriptionsList
Paymentfrequency paymentFrequency;
LocalDate firstPaymentDate;
#Stereotype("MONEY")
BigDecimal paymentAmount;
#ManyToOne(fetch=FetchType.LAZY)
#DescriptionsList
Methodofpayment methodOfPayment;
#ReadOnly
#Stereotype("MONEY")
#Calculation("paymentAmount * paymentFrequency.frequencyPerYear")
BigDecimal annualContribution;
}
And this the code for the entity with the collection of embeddables:
import javax.persistence.*;
import lombok.*;
#Entity #Getter #Setter
public class Paymentfrequency extends GenericType {
int frequencyPerYear;
// Payment is used as collection
#ElementCollection
#ListProperties("firstPaymentDate, paymentAmount, paymentFrequency,
methodOfPayment, annualContribution")
Collection<Payment> payments;
}
And this the result:
Note as the last column (annualContribution) is not recalculated when the operands change.
Why does not work #Calculation in this case?
#Calculation only works if all the operands are displayed in the user interface. In your case paymentFrequency.frequencyPerYear is not displayed given paymentFrequency is a reference displayed as #DescriptionsList.
Don't worry, just use a regular Java calculated property instead. In this way:
#Stereotype("MONEY")
#Depends("paymentAmount, paymentFrequency.id")
public BigDecimal getAnnualContribution() {
// You should refine the below code to lead with nulls
return getPaymentAmount().multiply(getPaymentFrequency().getFrequencyPerYear());
}
Learn more about calculated properties here:
https://openxava.org/OpenXavaDoc/docs/basic-business-logic_en.html

spring-data-mongodb delete function doesn't work?

I'm using spring-data -mongodb to do crud operations (create , read , update , delete), but
the delete function doesn't work and I don't know why? . Here is my code.
import org.bson.types.Binary;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#ToString
#Getter
#Setter
#Document(collection = "patterns")
public class Pattern {
#Id
#Field
private String id;
#Field
#Indexed(unique = true)
private String name;
#Field
private String status;
#Field
private Binary patternFile;
}
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import fod.pfe7.administratorportal.domain.Pattern;
public interface PatternRepository extends MongoRepository<Pattern, String> {
List<Pattern> findByName(String name);
}
in my controller I do .
patternRepository.findByName(patternName).forEach(pattern -> {
patternRepository.deleteById(pattern.getId());
result.put("status", 0);
result.put("message", "pattern deleted successfuly");
});
Your data might have been created by other system, which use different presentation of "_id" (says String). With newer version of spring data mongodb, you can use #MongoId instead of #Id to control this.
In my case, the later deletes record correctly.
#Id private String id; produces
Remove using query: { "_id" : { "$oid" : "60ed51ce597826297941ade4"}} in collection: sample.
#MongoId(FieldType.STRING) private String id; produces
Remove using query: { "_id" : "60ed51ce597826297941ade4"} in collection: sample.
Maybe a little late...
I got the same error and saw that the delete query did not include the Object_Id, so the findByID method was not working either.
The solution for me was to include the targetType in the #Field annotation:
#Field(name = "_id", targetType = FieldType.OBJECT_ID)

Spring boot JPA no returning existing result using findById

I have created a pretty small and simple Spring Boot app using the Oracle database and some JPA queries.
This is the code snippet which is not returning data, which is actually exists in database.
letterRecipientNonOas = letterRecipientNonOasRepository
.findById(Long.valueOf(letterRecipientDTO.getNonOas().getId()))
.orElseThrow(() -> new EntityNotFoundException(LetterRecipientNonOas.class,
Constant.MESSAGE_ENTITY_NOT_FOUND));
here findById is returning empty result set.
this is my repository
package com.care.document.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.care.document.model.LetterRecipientNonOas;
/**
* The Interface LetterRecipientNonOasRepository.
*/
#Repository
public interface LetterRecipientNonOasRepository extends PagingAndSortingRepository<LetterRecipientNonOas, Long> {
Optional<LetterRecipientNonOas> findByLetterId(Long id);
Optional<LetterRecipientNonOas> findByTitleIgnoreCase(String title);
List<LetterRecipientNonOas> findByTitleContainingIgnoreCase(String title);
List<LetterRecipientNonOas> findAllByTitleIgnoreCaseAndIdNot(String title, Long recipientId);
List<LetterRecipientNonOas> findAllByIdAndLetterId(long id, long letterId);
}
and this is my model class:
package com.care.document.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import org.springframework.lang.Nullable;
import com.care.admin.model.BaseEntity;
import com.care.admin.util.CommonUtil;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Entity
#Table(name = "letter_recipient_non_oas")
public class LetterRecipientNonOas extends BaseEntity implements Serializable {
#Id
Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "letter_id")
Letter letter;
Integer recipientType; // Action/Info
//byte recipientSubType; // Internal/External/NonOAS
byte recipientCategory; //Internal/External
int orderNo;
String title;
#Nullable
String remarks;
String address;
#PrePersist
private void prePersist() {
this.id = CommonUtil.generateID(this.atRegion);
}
}
I tested, tried different ways but of no use.
There are a couple of scenarios how one might get this impression:
You are looking at the wrong database.
The data isn't there yet when you try to load it, but is when you check.
JPAs caches are known to create such scenarios rather efficiently.
The data looks a little different than you think. This could be caused by invisible or easy to miss content like spaces or even control characters.
You check the database within the transaction that created the data or with a session that allows dirty reads and the insert that created the data wasn't committed yet.

How to save timestamp in UTC format for Audit fields #CreatedDate, #LastModifiedDate in Spring JPA

This is my Base Class for Entities with audit fields. For fields #CreatedDate, #LastModifiedDate, by default it is saving my system time. My requirement is to save timestamp in UTC.
Does anyone have a solution of this?
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import lombok.Data;
#MappedSuperclass
#Data
#EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
#LastModifiedDate
#Column(name="last_modified_datetime")
private LocalDateTime lastModifiedDateTime;
#CreatedDate
#Column(name="created_datetime")
private LocalDateTime createdDateTime;
}
This is problem of time zone. use this code for spring boot.
#PostConstruct
public void setTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
}

Issue in JPA Cascade Save with EmbeddedId in child

I am having three class. Person,vehicle and a association class to link the person and vehicle
Person
package entity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="PERSON")
public class Person {
#EmbeddedId
private PKperson pkPerson;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade=CascadeType.ALL,mappedBy="person")
private Set<PersonVehAssnVO> personVehAssnVOSet=new HashSet<PersonVehAssnVO>();
//getters & setters
}
PKperson
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Embeddable;
#Embeddable
public class PKperson implements Serializable {
#Column(name="NAME", nullable=false)
private String name;
#Column(name="DOB_DT", nullable=false)
private Date dobDt;
}
Vehicle
package entity;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.OneToMany;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="VEHICLE")
public class Vehicle {
#Id
#Column(name="VEHICLE_ID",unique=true, nullable=false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_name")
#SequenceGenerator(allocationSize = 1, name = "seq_name", sequenceName = "SEQ_VEHICLE_ID")
private Long vehicleId;
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(cascade=CascadeType.ALL,mappedBy="vehicle")
private Set<PersonVehAssnVO> personVehAssnVOSet=new HashSet<PersonVehAssnVO>();
private String vehicleName;
//getters & setters
}
Person Vehicle Association
package entity;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
#Entity
#Table(name ="PERSON_VEHICLE_ASSOC")
public class PersonVehAssnVO {
#EmbeddedId
private PKperson pkPerson;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "pkPerson.name",referencedColumnName ="NAME"),
#JoinColumn(name = "pkPerson.dobDt",referencedColumnName ="DOB_DT")})
private Person person;
#ManyToOne
#JoinColumn(name = "VEHICLE_ID", referencedColumnName = "VEHICLE_ID")
private Vehicle vehicle;
//getters & setters
}
//**Save Method**
PKperson pkPerson = new PKperson();
SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = dtFormat.parse("1984-12-14");
pkPerson.setName("Magesh");
pkPerson.setDobDt(date1);
Person person = new Person();
person.setPKperson(pkPerson);
Vehicle vehicle = new Vehicle();
vehicle.setName("Honda350");
PersonVehAssnVO perVehAssnVO = new PersonVehAssnVO();
PersonVehAssnVO.setPKperson(pkPerson);
PersonVehAssnVO.setVehicle(vehicle);
Set<PersonVehAssnVO> assocSet = new HashSet<PersonVehAssnVO>();
assocSet.add(PersonVehAssnVO);
person.setpersonVehAssnVOSet(assocSet);
vehicle.setpersonVehAssnVOSet(assocSet);
Session session = getHibernateTemplate().getSessionFactory().openSession();
transaction = session.beginTransaction();
transaction.begin();
session.save(person);
transaction.commit();
//=============================================================
While Executing the above save logic I am getting error ": [entity.PersonVehAssnVO#component[name,dobDt]{dobDt=magesh, dobDt=1984-12-14 00:00:00}]"
Show Sql Gives "select personVehAssnVO_.NAME, personVehAssnVO_.DOB_DT, personVehAssnVO_.VEHICLE_ID as vehicle_34 from PERSON_VEHICLE_ASSOC where personVehAssnVO_.NAME=? and personVehAssnVO_.DOB_DT=?"
I want to save Person,Vehicle and association in a single save means CASCADE ALL When I save Person.
Any help appreciated
Mark the date in PKPerson with the #Temporal annotation:
#Temporal(TemporalType.TIME)
#Column(name="DOB_DT", nullable=false, length = 8)
private Date dobDt;
According to the Java Doc
This annotation must be specified for persistent fields or properties
of type java.util.Date and java.util.Calendar. It may only be
specified for fields or properties of these types.
The Temporal annotation may be used in conjunction with the Basic
annotation, the Id annotation, or the ElementCollection annotation
(when the element collection value is of such a temporal type.
And according to this SO question:
In plain Java APIs, the temporal precision of time is not defined.
When dealing with temporal data you might want to describe the
expected precision in database. Temporal data can have DATE, TIME, or
TIMESTAMP precision (ie the actual date, only the time, or both). Use
the #Temporal annotation to fine tune that.
I hope this solves your problem. You can interchange the TemporalType with others that match your field type in the database. The column length also can be changed accordingly.
Edit
I think you also need to remove the mappedBy="person" and mappedBy="vehicle" from the annotation of the PersonVehAssnVO sets in the Person and Vehicle classes and replace them with full column properties so that these classes can be the owners of the relationship. Otherwise when you save a person, it will ignore updating any properties marked with the mappedby annotation because this means the Person is not the owner of that relationship.

Categories