I'm using Hibernate 5 and Spring 3.2.4. I'm deigning a User entity in which I want to include a reference to the user that has created the entity - so a self reference. The self reference itself isn't too problematic, but I want to specify the field as non null. Is this possible? How do I create the first entry in the DB if the field is non null as there referenced entity does not already exist?
Ex:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long User.id;
@NotNull
private String username;
private String password;
@NotNull
private User user;
// getters and setters omitted for brevity
}
If I try:
User u = new User();
u.setUsername("username");
u.setCreatedBy(u);
and try to persist u
, I get the following error message:
Caused by: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.domain.User.createdBy -> com.domain.User
I understand that Hibernate is complaining that it cannot reference a transient instance (ie: u
), but I cannot persist u
unless I have an non-null User that I can reference. But in an empty DB, there is no such entry.
Is this kind of configuration impossible to do? Or is there a way around this?
I don't understand this Roo annotations and I don't use Hibernate-specific annotations, only JPA. I don't have any issues with self references. But I have some hints fo you:
@ManyToOne
annotation.@NotNull
annotation (or nullable
field in @Column
) does not affect mapping, only DDL generation. I don't use DDL generation from domain model, do I never specify this. Instead I use optional
field of @ManyToOne
.NOT NULL
constraint. So either use sequence-based identifier generator or remove constraint. I would use first.optional
field of @ManyToOne
to false
, when you have NOT NULL
constraint. Otherwise Hibernate attempts to make two queries: insert with createdBy_id
set to NULL
and then update createdBy_id
. And the first query fails with NOT NULL
contraint enabled.I found a solution for this. You must use a Sequence generator for your ID (instead of the default auto generated IDs). Then it works.
@Entity
public class UserModel {
/**
* We must use a sequence for generating IDs,
* because of the self reference .
* https://vladmihalcea.com/2014/07/15/from-jpa-to-hibernates-legacy-and-enhanced-identifier-generators/
*/
@Id
@GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE)
@SequenceGenerator(name = "sequence", allocationSize = 10)
private Long id;
/** reference to a parent user, e.g. the manager */
@ManyToOne(optional = false)
@NotNull
UserModel parentUser;
[...]
The reason is the following: When Hibernate tries to insert a new User it also tries to validate the reference to the parentUser. But that will fail, for the first user we want to insert, or will also fail when a user references himself.
But when IDs are generated with a sequence, then the new/next ID is already known at the time of insert.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With