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
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.
I add to my Entity
#Version
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version")
private Date version;
and something strange happend. When i update, hibernate tells thath key already exists. How #version filed affect my Entity? I have no idea why it happend. When i remove this #version field everything works. I also use #Audited annotation.
My Entity:
private static final long serialVersionUID = 1636824190907788517L;
#Id
#NotNull
#Column(name = "id")
private UUID id;
#Version
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version")
private Date version;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "user", nullable = false)
private User user;
#Column(name = "purpose", length = 100)
protected String comment;
#OneToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "eq_id", nullable = false)
protected BasicEquipment equip;
#OneToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "eq_id2", nullable = false)
protected BasicEquipment equip2;
Error:
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement (...)
org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(Standaorg.hibernate.engine.jdbc.sporg.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatch
org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTra
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pk_entity"
Did you try this solution?
http://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking
Under some circumstances, problems may occur when versioned updates
are used together with batch updates. It has happened to me in the
past with a given version of Oracle 11g and Hibernate, for example.
The Oracle JDBC driver was not able to extract the correct number of
updated rows count in JDBC batch statements execution.
If you are also facing this problem, you may check if you have set the
Hibernate property hibernate.jdbc.batch_versioned_data to true. When
this setting is true, Hibernate will use batch updates even for
updates that are made against versioned data, ie. updates that need to
use the updated rows count in order to check for concurrent updates.
Since the JDBC driver may not return the correct updated rows count,
Hibernate will not be able to detect if concurrent updates actually
happened. The default value for this setting in Hibernate is false, so
it will not use batch updates when it detects that versioned data
updates are going to be executed in a given flush operation.
This is of course a specific scenario with Oracle 11g that is easily
worked around, as we have just seen.
How do I set a default value in Hibernate field?
If you want a real database default value, use columnDefinition:
#Column(name = "myColumn", nullable = false, columnDefinition = "int default 100")
Notice that the string in columnDefinition is database dependent. Also if you choose this option, you have to use dynamic-insert, so Hibernate doesn't include columns with null values on insert. Otherwise talking about default is irrelevant.
But if you don't want database default value, but simply a default value in your Java code, just initialize your variable like that - private Integer myColumn = 100;
Use hibernate annotation.
#ColumnDefault("-1")
private Long clientId;
Recreate the table if it already exists for the changes to take effect.
You can use #PrePersist anotation and set the default value in pre-persist stage.
Something like that:
//... some code
private String myProperty;
//... some code
#PrePersist
public void prePersist() {
if(myProperty == null) //We set default value in case if the value is not set yet.
myProperty = "Default value";
}
// property methods
#Column(nullable = false) //restricting Null value on database level.
public String getMyProperty() {
return myProperty;
}
public void setMyProperty(String myProperty) {
this.myProperty= myProperty;
}
This method is not depend on database type/version underneath the Hibernate. Default value is set before persisting the mapping object.
what about just setting a default value for the field?
private String _foo = "default";
//property here
public String Foo
if they pass a value, then it will be overwritten, otherwise, you have a default.
Default entity property value
If you want to set a default entity property value, then you can initialize the entity field using the default value.
For instance, you can set the default createdOn entity attribute to the current time, like this:
#Column(
name = "created_on"
)
private LocalDateTime createdOn = LocalDateTime.now();
Default column value using JPA
If you are generating the DDL schema with JPA and Hibernate, although this is not recommended, you can use the columnDefinition attribute of the JPA #Column annotation, like this:
#Column(
name = "created_on",
columnDefinition = "DATETIME(6) DEFAULT CURRENT_TIMESTAMP"
)
#Generated(GenerationTime.INSERT)
private LocalDateTime createdOn;
The #Generated annotation is needed because we want to instruct Hibernate to reload the entity after the Persistence Context is flushed, otherwise, the database-generated value will not be synchronized with the in-memory entity state.
Instead of using the columnDefinition, you are better off using a tool like Flyway and use DDL incremental migration scripts. That way, you will set the DEFAULT SQL clause in a script, rather than in a JPA annotation.
Default column value using Hibernate
If you are using JPA with Hibernate, then you can also use the #ColumnDefault annotation, like this:
#Column(name = "created_on")
#ColumnDefault(value="CURRENT_TIMESTAMP")
#Generated(GenerationTime.INSERT)
private LocalDateTime createdOn;
Default Date/Time column value using Hibernate
If you are using JPA with Hibernate and want to set the creation timestamp, then you can use the #CreationTimestamp annotation, like this:
#Column(name = "created_on")
#CreationTimestamp
private LocalDateTime createdOn;
If you want to do it in database:
Set the default value in database (sql server sample):
ALTER TABLE [TABLE_NAME] ADD CONSTRAINT [CONSTRAINT_NAME] DEFAULT (newid()) FOR [COLUMN_NAME]
Mapping hibernate file:
<hibernate-mapping ....
...
<property name="fieldName" column="columnName" type="Guid" access="field" not-null="false" insert="false" update="false" />
...
See, the key is insert="false" update="false"
One solution is to have your getter check to see if whatever value you are working with is null (or whatever its non-initialized state would be) and if it's equal to that, just return your default value:
public String getStringValue(){
return (this.stringValue == null) ? "Default" : stringValue;
}
Use #ColumnDefault() annotation. This is hibernate only though.
I searched for this and found many answers to default value for column.If you want to use default value defined in SQL Table then in #Column Annotation use "insertable = false". insertable
#Column(name = columnName, length = lengthOfColumn, insertable = false)
If you are using columnDefination it #Column annotation may be it won't work as it is Database dependent.
Working with Oracle, I was trying to insert a default value for an Enum
I found the following to work the best.
#Column(nullable = false)
#Enumerated(EnumType.STRING)
private EnumType myProperty = EnumType.DEFAULT_VALUE;
To use default value from any column of table. then you must need to define #DynamicInsert as true or else you just define #DynamicInsert. Because hibernate takes by default as a true.
Consider as the given example:
#AllArgsConstructor
#Table(name = "core_contact")
#DynamicInsert
public class Contact implements Serializable {
#Column(name = "status", columnDefinition = "int default 100")
private Long status;
}
You can use the java class constructor to set the default values. For example:
public class Entity implements Serializable{
private Double field1
private Integer field2;
private T fieldN;
public Entity(){
this.field1=0.0;
this.field2=0;
...
this.fieldN= <your default value>
}
//Setters and Getters
...
}
I tried it. when i did that
#Column(name = "is_sale", columnDefinition = "default false")
private boolean isSale = false;
he did not add. And when I did
#Column(name = "is_sale", columnDefinition = "bool default false")
private boolean isSale = false;
in this case Hibernate generated such sql
alter table if exists customer_product add column is_sale bool default false
and it helped me
<property name="age" type="integer">
<column name="age" not-null="false" default="null" />
</property>
i'am working with hibernate 5 and postgres, and this worked form me.
#Column(name = "ACCOUNT_TYPE", ***nullable***=false, columnDefinition="varchar2 default 'END_USER'")
#Enumerated(EnumType.STRING)
private AccountType accountType;
If you want to set default value in terms of database, just set #Column( columnDefinition = "int default 1")
But if what you intend is to set a default value in your java app you can set it on your class attribute like this: private Integer attribute = 1;
Suppose we have an entity which contains a sub-entity.
Using insertable = false, updatable = false on the entity prevents the entity from creating new sub-entities and preceding the default DBMS value. But the problem with this is that we are obliged to always use the default value or if we need the entity to contain another sub-entity that is not the default, we must try to change these annotations at runtime to insertable = true, updatable = true, so it doesn't seem like a good path.
Inside the sub-entity if it makes more sense to use in all the columns insertable = false, updatable = false so that no more sub-entities are created regardless of the method we use (with #DynamicInsert it would not be necessary)
Inserting a default value can be done in various ways such as Default entity property value using constructor or setter. Other ways like using JPA with columnDefinition have the drawback that they insert a null by default and the default value of the DBMS does not precede.
Insert default value using DBMS and optional using Hibernate
But using #DynamicInsert we avoid sending a null to the db when we want to insert a sub-entity with its default value, and in turn we allow sub-entities with values other than the default to be inserted.
For inserting, should this entity use dynamic sql generation where only non-null columns get referenced in the prepared sql statement?
Given the following needs:
The entity does not have the responsibility of creating new sub-entities.
When inserting an entity, the sub-entity is the one that was defined as default in the DBMS.
Possibility of creating an entity with a sub-entity which has a UUID other than the default.
DBMS: PostgreSQL | Language: Kotlin
#Entity
#Table(name = "entity")
#DynamicInsert
data class EntityTest(
#Id #GeneratedValue #Column(name = "entity_uuid") val entityUUID: UUID? = null,
#OneToOne(cascade = [CascadeType.ALL])
#JoinColumn(name = "subentity_uuid", referencedColumnName = "subentity_uuid")
var subentityTest: SubentityTest? = null
) {}
#Entity
#Table(name = "subentity")
data class SubentityTest(
#Id #GeneratedValue #Column(name = "subentity_uuid", insertable = false, updatable = false) var subentityUUID: UUID? = null,
#Column(insertable = false, updatable = false) var name: String,
) {
constructor() : this(name = "")
}
And the value is set by default in the database:
alter table entity alter column subentity_uuid set default 'd87ee95b-06f1-52ab-83ed-5d882ae400e6'::uuid;
GL
Source 1
Source 2
we can have getter that annotates #Column
all #column should be annotated in getter alone instead of direct variable declaration. by this way, we can resolve it.
#Column(name = "string_value")
public String getStringValue(){
return (this.stringValue == null) ? "Default" : stringValue;
}
thanks to you guys my knowlegde on hibernate has been improve dratiscally.
now i hit a block here about current_timestamp.
here is my codes
#Column(name="DATE_CREATED", insertable=false, updatable=false, columnDefinition="timestamp default current_timestamp")
#org.hibernate.annotations.Generated(value=GenerationTime.INSERT)
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date dateCreated;
#Column(name="LAST_MODIFIED", insertable=false, updatable=false, columnDefinition="datetime")
#org.hibernate.annotations.Generated(value=GenerationTime.ALWAYS)
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date lastModified;
i want date_created to get the current_timestamp and i want the lastmodified to insert the time for each updates.apparently i can't have 2 current_timestamp fields on the same table.Is there other ways to achieve that? thanks for reading
This is not related to Hibernate per se. Your annotations as specified above tell Hibernate that the values are going to be generated by the database and thus need to be reloaded after entity is inserted / updated.
If that's the way you want to go with, you need to configure your database (by creating a trigger, for example) to populate date_created / last_modified columns as needed.
Another approach is to not mark those fields as generated and instead update them in your java code. If you're using JPA (via Hibernate EntityManager), it's rather trivial to do this via #PrePersist / #PreUpdate callback method:
#PreUpdate
#PrePersist
public void updateTimeStamps() {
lastModified = new Date();
if (dateCreated==null) {
dateCreated = new Date();
}
}
You could achieve the same thing with hibernates #CreationTimestampand #UpdateTimestamp annotations e.g.
#Column(name = "CREATED")
#CreationTimestamp
private LocalDateTime created;
#Column(name = "LAST_UPDATED")
#UpdateTimestamp
private LocalDateTime lastUpdated;