Created by , Updated by column cannot be null spring jpa error - java

I am using spring boot and jpa and i want to save data in table.
I have database table constraint not null on createdBy, updatedBy, updationDate, creatingDate columns.
I have similar DTO to entity and above mentioned audit fields are not in DTO but only in entity so meaning user don't send audit information.
On entity i am using this #EntityListeners(AuditingEntityListener.class).
Problem is when i try to update entity by rep.save(entity) i get this error "Column 'CreatedBy' cannot be null
My entity is using auditing entity listeners and it looks similar to this
#Column(name = "isactive")
private boolean active;
#CreatedBy
#Column(name = "createdby")
private String createdBy;
#CreatedDate
#Column(name = "creationdate")
private Instant creationDate;
#LastModifiedBy
#Column(name = "lastupdateby")
private String lastUpdateBy;
#LastModifiedDate
#Column(name = "lastupdatedate")
private Instant lastUpdateDate;
Note: If i try to create new object, it gets saved and worked fine and also audit information in database like created by updated by is also populated using auditing entity listener.
But when it try to update the same object i get the error of createdBy cannot be null, i am assuming these audit fields createdBy updatedBy .... should also be populated of filled by auditEntityListener the same way i create it by post request.

you can use the updatable = false flag, e.g.
#Column(name = "createdby", updatable = false)
and
#Column(name = "creationdate", updatable = false)
that helped me to solve this issue.

I got the solution, When we need to update the entity that is using AuditEntityListener
i updated only the changed fields in entity comparing to DTO.
MapStruct made it easy
void updateEntity(#MappingTarget Entity target, DTO dto);
now save the updated entity.

Have a look how to use Audit Aware in link

Related

Spring Data JPA Returning Proxy Object For One Record and Real Object For One Record

I am using spring-data-jpa to read data from db.
JPA Entity
#Entity
#Table(name = "ICM_STATUSES")
public class IcmMdStatuses implements Serializable {
#Id
#Column(name = "STATUS_INTERNAL_IDENTIFIER")
private long statusInternalIdentifier;
#Column(name = "STATUS_IDENTIFIER")
private String statusIdentifier;
#Column(name = "STATUS_NAME")
private String statusName;
#Column(name = "STATE_NAME")
private String stateName;
#Column(name = "IS_ACTIVE")
private String isActive= "Y";
#Column(name = "CREATED_BY")
private String createdBy;
#CreationTimestamp
#Column(name = "CREATE_DATE")
private Date createdDate;
#Column(name = "UPDATED_BY")
private String updatedBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATE_DATE")
private Date updateDate;
}
JPA Repository
public interface StatusRepository extends JpaRepository<IcmMdStatuses, Long> {
Optional<IcmMdStatuses> findByStatusIdentifier(String statusIdentifier);
}
DB Table Data
Problem:
If I try to fetch Open status record. I am getting Hibernate Proxy Object instead of real object.
If I try to fetch Reopen status record. i am getting real object.
Except for Open status, for the rest all statuses i am getting real objects.
I could able to get the real object using Hibernate.unproxy(-)
Problem
MyEntity entity = new MyEntity();
//If i use any other status except Open the below line saves pk of that particular status.
entity.setFromStatus(statusRepository.findByStatusIdentifier("Open"));//saving null in db
entity.setToStatus(statusRepository.findByStatusIdentifier("Reopen"));//saving value 93(PK of Reopen status)
myRepo.save(entity);
Please help to understand what's the actual issue, as i am experiencing this issue only for Open Status, rest all works as expected.
The problem is most probably due to open-session-in-view and the fact that you loaded some other object that refers to this Open status object. Since that other object did not load the Open status object, it created a proxy for it which is then part of the persistence context. The next time you load that object, you retrieve that proxy instead of the real object because Hibernate must maintain the object identity guarantee for a persistence context.

JPA Auditing LastModifiedBy/LastModifiedDate are null when being accessed in the transaction method

I have my auditing set up as shown below, and they work fine. The problem is when I want to access them within the transactional method before the update, the update id/date are always null and I'm not sure why.
#CreatedBy
#Column(name = "CREATE_ID", updatable = false, nullable = false)
private String createId;
#LastModifiedBy
#Column(name = "UPDATE_ID", nullable = false)
private String updateId;
#CreatedDate
#Column(name = "CREATE_DATE", updatable = false, nullable = false)
private Date createDate;
#LastModifiedDate
#Column(name = "UPDATE_DATE", nullable = false)
private Date updateDate;
The create/update methods that are calling save.
Note: BOTH of these work fine, creating/updating records in the database with the correct create/update audit values. The issue is that I cannot access update id/date within the update method and I'm not sure why/how to fix it.
#Override
#Transactional
public MyObj create(MyObj myObj) {
MyObj createdMyObj = myObjRepo.save(myObj);
System.out.println(createdMyObj.getCreateId()); // This works fine
return createdMyObj;
}
#Override
#Transactional
public MyObj update(MyObj myObj) {
MyObj updatedMyObj = myObjRepo.save(myObj);
System.out.println(updatedMyObj.getUpdateId()); // This is null
return updatedMyObj;
}
The auditing feature of Spring Data JPA is based on JPA lifecycle events and the event PreUpdate used to set the last-modified columns are only triggered when the JPA implementation actually updates the database which is in many cases at the end of the transaction.
See section 3.5.3 of the JPA specification:
The PreUpdate and PostUpdate callbacks occur before and after the database update operations to entity data respectively. These database operations may occur at the time the entity state is updated or they may occur at the time state is flushed to the database (which may be at the end of the transaction).
Therefore, if you want these values to be set you need to flush the persistence context.

Getting certain value from the foreign entity using JPA

I have 2 entities User and Profile where one user has one profile.
The User entity mapping is pretty clear and looks like this:
#Entity
public class User {
#Id
private String id;
#Column(unique = true, nullable = false)
private String email;
#Column(unique = true, nullable = false)
private String name;
}
So the question is about Profile entity mapping, the tricky thing
here is that Profile includes user's email(not entire user's entity), but it shouldn't be either updated or stored by Profile, so the email is readonly attribute from the foreign User entity.
I used the following Profile's entity mapping for getting User's email:
#Entity
public class Profile {
#Id
private String userId;
#PrimaryKeyJoinColumn
private User user;
#Basic
private String firstName;
#Basic
private String lastName;
// ...
public String getEmail() {
return user.getEmail();
}
}
So i decided to join the entire entity and delegate the work to it.
As far as i understand it is impossible to use #JoinColumn in couple with #Column like this:
#OneToOne
#JoinColumn(name = "userId", insertable = false, updatable = false)
#Column(name = "email")
private String email;
I am also not sure about using of #SecondaryTable as it seems that it is designed for a different purpose.
Is there any better approach for getting foreign entity field using JPA mappings?
JPA Backend: EclipseLink 2.6.2
That's not really what JPA was designed to do. Getting the email by just calling user.getEmail() is the cleanest option you have.
You shouldn't be worried too much about loading the entire user; the way I see it it's a single join, and JPA should do it for you. The performance impact should be minimal. (you can simple not expose the internal user object to not impact your object design too much. When using JPA, you're always limiting your OO design options though).
If you were using hibernate, the story would be different. Then you could use the #Formula annotation. It would not be more performant though. Eclipselink has nothing like it.

org.hibernate.TransientObjectException if any many-to-one fields are null (or not selected in form)

I am using jpa with play framework.I have an entity JobseekerDetails
#Entity
public class JobseekerDetails {
#Id
#Column(name = "jobseekerDetails_id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long jobseekerDetails_id;
#ManyToOne
#JoinColumn(name = "basicEducation_id")
private JobseekerFormBasicEducation basicEducation;
#ManyToOne
#JoinColumn(name = "masterEducation_id")
private JobseekerFormMasterEducation masterEducation;
#ManyToOne
#JoinColumn(name = "doctrateEducation_id")
private JobseekerFormDoctrateEducation doctrateEducation;
#ElementCollection
private List<String> certificateName =new ArrayList<String>();
#Column(length = 3000)
private String resume;
private Long experience;
private String skills;
private String resumePath;
#ManyToOne
#JoinColumn(name = "industry_id")
private JobseekerFormIndustry industry;
#ManyToOne
#JoinColumn(name = "functionalArea_id")
private JobseekerFormFunctionalArea functionalArea;
}
which have a many-to-one relation with other entities like JobseekerFormFunctionalArea , JobseekerFormIndustry etc.These entities have fixed value which is already saved in the database.
When JobseekerDetails is saved all its details should be saved with corresponding manytoone relation ids but donot save to Entity JobseekerFormFunctionalArea and JobseekerFormIndustry as they are predefined
My problem is that when i save(through my form) all the manytoone relation fields ids in JobseekerDetails it is saved properly but when submit my form without selecting any value in any manytoone relation fields For ex if i dont select anything in my fuctionalArea_id field it gives the below exception
org.hibernate.TransientObjectException:object references an unsaved transient instance - save the transient instance before flushing
If I select all the fields the details are saved but if I dint select anyone field which is mapped manytoone in my model then it gives above exception
But jpa automatically set nullable=true then why this happend
I have searched a bit and found that this problem can be solved by adding cascade .I added cacade type Merge but getting the above same exception.
I also tryed setting nullable=true but getting same error
On setting cascade = CascadeType.ALL and cascade = CascadeType.PERSIST I am getting below exception
PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist:
Any help would be appreciated
When you don't select any 'basicEducation' in the form and you are saving form then there is new object there with empty id. So you have:
jobseekerDetails.basicEducation = new JobseekerFormBasicEducation ()
This causes TransientObjectException
To avoid it you have to set
jobseekerDetails.basicEducation=null
before saving.

Setting a JPA timestamp column to be generated by the database?

In my SQL Server 2000 database, I have a timestamp (in function not in data type) column of type DATETIME named lastTouched set to getdate() as its default value/binding.
I am using the Netbeans 6.5 generated JPA entity classes, and have this in my code
#Basic(optional = false)
#Column(name = "LastTouched")
#Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
However when I try to put the object into the database I get,
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched
I've tried setting the #Basic to (optional = true), but that throws an exception saying the database doesn't allow null values for the TIMESTAMP column, which it doesn't by design.
ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.
I previously got this to work in pure Hibernate, but I have since switched over to JPA and have no idea how to tell it that this column is supposed to be generated on the database side. Note that I am still using Hibernate as my JPA persistence layer.
I fixed the issue by changing the code to
#Basic(optional = false)
#Column(name = "LastTouched", insertable = false, updatable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
So the timestamp column is ignored when generating SQL inserts. Not sure if this is the best way to go about this. Feedback is welcome.
I realize this is a bit late, but I've had success with annotating a timestamp column with
#Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
This should also work with CURRENT_DATE and CURRENT_TIME. I'm using JPA/Hibernate with Oracle, so YMMV.
#Column(nullable = false, updatable = false)
#CreationTimestamp
private Date created_at;
this worked for me.
more info
Add the #CreationTimestamp annotation:
#CreationTimestamp
#Column(name="timestamp", nullable = false, updatable = false, insertable = false)
private Timestamp timestamp;
If you are doing development in Java 8 and Hibernate 5 Or Spring Boot JPA then use following annotation directly
in your Entity class. Hibernate gets the current timestamp from the VM and will insert date and time in database.
public class YourEntity {
#Id
#GeneratedValue
private Long id;
private String name;
#CreationTimestamp
private LocalDateTime createdDateTime;
#UpdateTimestamp
private LocalDateTime updatedDateTime;
…
}
I do not think that every database has auto-update timestamps (e.g. Postgres). So I've decided to update this field manually everywhere in my code. This will work with every database:
thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);
There are reasons to use triggers, but for most projects, this is not one of them. Triggers dig you even deeper into a specific database implementation.
MySQL 5.6.28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) seems to be very forgiving, not requiring anything beyond
#Column(name="LastTouched")
MySQL 5.7.9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) only works with
#Column(name="LastTouched", insertable=false, updatable=false)
not:
FAILED: removing #Temporal
FAILED: #Column(name="LastTouched", nullable=true)
FAILED: #Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
My other system info (identical in both environments)
hibernate-entitymanager 5.0.2
hibernate-validator 5.2.2
mysql-connector-java 5.1.38
I have this working well using JPA2.0 and MySQL 5.5.10, for cases where I only care about the last time the row was modified. MySQL will create a timestamp on first insertion, and every time UPDATE is called on the row. (NOTE: this will be problematic if I cared whether or not the UPDATE actually made a change).
The "timestamp" column in this example is like a "last-touched" column.x`
The code below uses a separate column "version" for optimistic locking.
private long version;
private Date timeStamp
#Version
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
// columnDefinition could simply be = "TIMESTAMP", as the other settings are the MySQL default
#Column(name="timeStamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
#Temporal(TemporalType.TIMESTAMP)
public Date getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Date timeStamp) {
this.timeStamp = timeStamp;
}
(NOTE: #Version doesn't work on a MySQL "DATETIME" column, where the attribute type is "Date" in the Entity class. This was because Date was generating a value down to the millisecond, however MySQL was not storing the millisecond, so when it did a comparison between what was in the database, and the "attached" entity, it thought they had different version numbers)
From the MySQL manual regarding TIMESTAMP :
With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
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][1].
This also works for me:-
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATE_DATE_TIME", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
public Date getCreateDateTime() {
return createDateTime;
}
public void setCreateDateTime(Date createDateTime) {
this.createDateTime = createDateTime;
}
I'm posting this for people searching for an answer when using MySQL and Java Spring Boot JPA, like #immanuelRocha says, only have too #CreationTimeStamp to the #Column in Spring, and in MySQL set the default value to "CURRENT_TIMESTAMP".
In Spring add just the line :
#Column(name = "insert_date")
#CreationTimestamp
private Timestamp insert_date;
#Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
#Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`
This worked for me:
#Column(name = "transactionCreatedDate", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

Categories