I am developing a Java EE application using GlassFish 4.1, EclipseLink and Derby and noticed today that when I create an new Person entity the version of the newly created entity is 2 instead of 1. The following is my Person Entity.
@Entity
public class Person {
@Id
private Long id;
@Version
private Integer version;
private String name;
@OneToOne
private Portrait portrait;
@OneToMany(mappedBy = "person")
private List<Portrait> portraits;
...
}
The following is my Portrait entity.
@Entity
public class Portrait {
@Id
private Long id;
@Version
private Integer version;
private String name;
@ManyToOne
private Person person;
...
}
The following is the part of my stateless EJB createPerson method that results in a newly created Person entity with a version of 2.
Person person = new Person();
person.setName("Fred Smith");
em.persist(person);
Portrait portrait = new Portrait();
portrait.setName("Fred Smith Portrait");
portrait.setPerson(person);
portrait = portraitManager.createPortrait(portrait); //portraitManager is another stateless EJB.
person.setPortrait(portrait); // Commenting out this line results in newly created Person entity with a version of 1.
person.getPortraits().add(portrait);
If I comment out the person.setPortrait(portrait)
line above the Person entity is created with a version of 1.
I read in other posts that JPA will increment the version of an entity if a field changes or an owned relationship changes. After the method returns from the createPortrait method, I am changing an owned relationship but I am still in the same transaction so don't see why JPA needs to increment the version.
Why does JPA increment the version on my Person entity twice during the same transaction?
As requested in the comments, I turned on EclipseLink logging and observed the following during the normal flow:
- Application starts createPerson method.
- EclipseLink inserts row into person table.
- Application starts createPortrait method.
- EclipseLink inserts row into portrait table.
- Application completes createPortrait method.
- Application associates newly created portrait with person.
- EclipseLink updates row in person table setting the version to 2 and the portrait_id to the newly created portrait.
- Application completes createPerson method.
If I comment out the "person.setPortrait(Portrait);" command, the log shows me the following:
- Application starts createPerson method.
- EclipseLink inserts row into person table.
- Application starts createPortrait method.
- EclipseLink inserts row into portrait table.
- Application completes createPortrait method.
- Application completes createPerson method.
To be more specific with my question, why does EclipseLink update the version in step 7 of the normal flow? EclipseLink created the row with version 1 in step 2 and there is no way another transaction updated the row because the row only exists in this transaction until it commits.
I suspect the answer is that this is just the way that EclipseLink choose to work under this scenario.