4

I have an Account entity and I'm trying to persist it using save function. My code:

@Override
public Account createAccount(String pin) {

    Account account = new Account();
    account.setBalance(0L);
    account.setPin(pin);

    return accountRepository.save(account);

}

Now my entity class has an autogenerated field called accountNumber. My entity class:

@Entity
@Table(name = "accounts")
@Data
public class Account {

    @Column(name = "account_number", length = 32, insertable = false)
    private String accountNumber;

    private Long balance;


}

Now after calling save, the entity returned has accountNumber as null but i can see in the intellij database view that it is actually not null. All the other auto-generated fields like id etc are there in the returned entity just the accountNumber is null. Default value for accountNumber is set in the sql file :

ALTER TABLE accounts
  ALTER COLUMN account_number SET DEFAULT DefaultValueSerializer(TRUE, TRUE, 12);

Here, DefaultValueSerializer is the function which is generating the account number.

I've tried other solutions available here like using saveAndFlush() etc, nothing worked in my case. What can be an issue?

Talha Mir
  • 1,228
  • 11
  • 19
  • 2
    Because that isn't how hibernate works, it doesn't know anything about auto generating columns I your database and won't automagically update values like that. You will need to retrieve the `Account` freshly from the database to get the field. – M. Deinum Nov 30 '17 at 08:55
  • @M.Deinum Tried that as well. After saving i used `findOne` function to retrieve the account. Surprisingly the `accountNumber` returned is still `null`. And for some reason that `findOne` doesn't result in select query as i cannot see any hibernate query logged as a result of `findOne` function call. – Talha Mir Nov 30 '17 at 09:18
  • Because, as you noticed, that won't retrieve it from the database. With an ORM tool that will first check the first level cache if the desired entity with the requested id is already present in the cache and well it is so you get that instance. You will first have to clear the cache (`entitymanager.clear()`) and reload it or `refresh` (`entityManager.refresh`) the entity. – M. Deinum Nov 30 '17 at 09:25
  • 1
    You are indeed correct. I ended up using `@Generated(value = INSERT)` annotation for the `accountNumber` field. It let's the JPA know that the value is generated during Insertion time so it will query the value again from the DB to get the updated value after saving it. Thanks for pointing me in the right direction. – Talha Mir Nov 30 '17 at 10:22
  • Annotation `@Generated` seems to be `hibernate` specific so not `JPA`. – pirho Dec 04 '17 at 10:41

3 Answers3

1

As mentioned in comment Hibernate is not aware about what happens in database engine level so it does not see the value generated.

It would be wise to move generation of account number to JPA level instead of using db defaults.

I suggest you to study annotations @GeneratedValue and related stuff like @SequenceGenerator. That way the control of generating account number is in JPA level and there is no need for stuff like refreshing entity after save.

One starting point: Java - JPA - Generators - @SequenceGenerator

For non-id fields it is possible to generate value in method annotated with @PrePersist as other answer suggests but you could do the initialization already in the Accounts constructor .

Also see this answer for options.

pirho
  • 11,565
  • 12
  • 43
  • 70
0

You can create an annotated @PrePersist method inside the entity in which you set its fields to their default value.

That way jpa is going to be aware of the default.

There are other such annotation avaiable for different entity lifecycle event https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/listeners.html

P.s. if you decide to go this way remember to remove the insertable = false

Zeromus
  • 4,472
  • 8
  • 32
  • 40
0

Use

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

for your IDs. And also leave your saving to saveAndFlush so you can immediately see the changes, If any. I'd also recommend separating IDs and account numbers. They should not be the same. Try debugging your program and see where the value stops passing around.

Subnom
  • 57
  • 2
  • 11