Hi!
Im am using Hibernate in "native mode" (not JPA), lets discuss the issue with two example entities (All Entities hav a String with a UUID as PK, the PK is generated in the constructor).
1. Developer 2. Project
Developer contains a unidirectional relation to Project:
@OneToOne(optional = true, cascade = { }, fetch = FetchType.LAZY) private Project project;
The Session is in FlushMode.COMMIT.
When I create one Developer and one Project, and save() (or persist()) them, the resulting SQL statements depend on the order of events:
d = new Developer() p = new Project() d.setProject(p) persist(d) // save(d) gives the same result persist(p) commit()
On flush/commit SQL is generated in the following order: select project, insert Developer, insert Project
Question: Why does Hibernate fire the select? It is after the two persist calls, so Hibernate could know the referenced project exists in the session.
When I move the persist-calls before the d.setProject(p), I get:
insert Developer, insert Project, update Developer
Why the update? All the statements are fired on flush/commit...
I found two solutions which result in two inserts (without update/select)
1. Marke the relation as CascadeType.PERSIST 2. Reorder the persist calls: First Project, second Developer
The second solution is feasible in this little example, but difficult in production code with many entities.
The first solution works when the PK is a String. But in a legacy system I have a composite key: String mandant, String objectId. In the relations, the foreighn shares the column mandant with the primary key, so I had to map relations like this:
@Column(name = "project", length = 35) private String projectObjectId;
@OneToOne(cascade = { }, fetch = FetchType.LAZY) @JoinColumns({ @JoinColumn(name="mandant", referencedColumnName="mandant", insertable=false, updatable=false), @JoinColumn(name="project", referencedColumnName="ObjectId", insertable=false, updatable=false) }) private Project project;
public void setProject(Project project) { this.project = project; projectObjectId = project != null ? project.getId().getObjectId() : null; }
In this case, a CascadeType.PERSIST does not help, which is not surprising because the relation is read only.
Is there any configuration or other trick which avoids the unnecessary SQLs? Do I have to order the persist-calls by myself? Another thing is Hibernates expects these calls when the entities are completely initialized, otherwise validation fails on non nullable properties. From a programming view, the easiest thing would be to call persist direct after the constructor call, so the entity is part of the Session and I can never forget to persist it before commit.
Regards
Roger
|