1

How can I add/persist a record/bean without a field so that it gets the default value?

Trying to make a minimal example, suppose I have the postgres table created as:

CREATE TABLE FOO(id int, ts timestamp without time zone default current_timestamp);

and I have

@Entity
@Table(name = "foo")
public class FooBean  {
    @Id
    @Column(name = "id", nullable = false)
    private int id;
    @Column(name = "ts", nullable = false, length = 50)
    private Instant ts;

    public int getId() {return id;}
    public Instant getTs() {return ts;}

    public void setId(int id) {
        this.id = id;
    }
    public void setTs(Instant ts) {
        this.ts = ts;
    }

}

And then e.g.

@ApplicationScoped
public class FooService {
    @Inject
    EntityManager em;

    @Transactional
    public boolean addAFoo(int id){
         //left out: make sure it is not already added, else return false, then:
         FooBean fooBean = new FooBean();
         fooBean.setId(id);
         em.persist(fooBean);
         return true;
    }
}

The problem here is that although I did not setup explicitly fooBean.ts, it is null, and so postgres does not assign the default value, but tries to set ts to null on the created record (and we get an error,cause the column is not nullable ).

How can this be overcome / how can I tell JPA to allow the DB to use the default value at insertion time?

ntg
  • 12,950
  • 7
  • 74
  • 95
  • 1
    JPA standard does not provide this feature AFAIK, but JPA providers may (see Hibernate's [@DynamicInsert](https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/DynamicInsert.html)/[@Entity(dynamicInsert)](https://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/annotations/Entity.html#dynamicInsert())). But really, just manage this in Java; I feel managing it in 2 places will cause confusion. – Nikos Paraskevopoulos Jun 09 '21 at 11:25
  • Normally I would agree, my problem is I need the time field to decide if some actions have expired, and want to use the DataBase's system clock time (in case one of the connecting systems clocks is messed up) So using the default from sql allows me to set the DB systems time... I ended up first quering the time from the DB and set it to that myself, so more or less what you sugest https://stackoverflow.com/questions/1659030/how-to-get-the-database-time-with-jpql/67873402#67873402 – ntg Jun 09 '21 at 12:40
  • 1
    I definitely see your point. Generally, I feel kind of weird implementing business functionalities in the DB. Another idea would be to have all the "connecting systems" post a message to a common message broker. The broker enhances the message with the timestamp when received it, then persists it. That might be an overkill - just mentioning for what it's worth. Good luck! – Nikos Paraskevopoulos Jun 09 '21 at 14:33
  • @pirho This is it! Not sure how i missed it. Though commenting on the answers, I think `@CreationTimestamp` should not be used, but instead `updatable = false, insertable = false)` https://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/annotations/CreationTimestamp.html : The property value will be set to the current *VM date* (not DB...). – ntg Jun 10 '21 at 09:33

0 Answers0