Optimistic Locking OneToMany Bidirectional

Hallo,…

Ich habe eine bidirektionale One-To-Many Beziehung zwischen Stadt (One) und Person (Many). (Beide Entitys haben eine Versionierung)
Nun möchte ich, dass sich die Version beider Entitys ändert, wenn ich aus der Liste einer Stadt eine Person wegnehme. (Standardmäßig wird nur der Owner, also die Person, hochgezählt)

Ein weiterer Punkt ist (oder auch ein Bug?), dass ich sozusagen versucht habe, das Verhalten via em.lock(stadt, LockModeType.OPTIMISTIC_FORCE_INCREMENT) in der Update- Methode zu erzwingen. Hier ist das komische, dass dieser Befehl nicht mehr funktioniert, sobald ich eine Person aus der Stadt entferne,… kommentiere ich den remove- Teil aus, wird die Version der Stadt hochgezählt.

Zusammengefasst: Ich möchte, dass beide Seiten der Beziehung hochgezählt werden, sobald ich die Liste verändere. Leider finde ich irgendwie kaum was zu dem konkreten Thema (beide Seiten hochzählen), besonders nicht zu OpenJPA. (EclipseLink / Hibernate bieten da etwas mehr Möglichkeiten)

Ich benutze übrigens OpenJPA 2.2.1.

Hier mal mein Beispiel- Code:

Stadt:

public class Stadt implements Serializable{
	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqStadt")
	@SequenceGenerator(name = "seqStadt", sequenceName = "stadtSeq")
	private Long id;

	@Version
	private Long version;

	@Column(nullable = true, unique = true)
	private String name;

	@OneToMany(mappedBy = "stadt", cascade = CascadeType.ALL)
	private List<Person> persons;
         
/**GETTER & SETTER*/

Person:

public class Person implements Serializable{
	  
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,generator="seqGenerator")
    @SequenceGenerator(name="seqGenerator",sequenceName="personSeq")
    private Long id;
    
    @Version
    private Long version;
    
    @ManyToOne()
    private Stadt stadt;

    @Column(nullable=true, unique=true)
    private String name;

   /** GETTER & SETTER*/
    ```

```public class Starter implements Serializable {
	private static EntityManager em;
	
	public static void main(String[] args) {
		em = Persistence.createEntityManagerFactory("openjpa")
				.createEntityManager();
		Person person1 = new Person("Person");
		Person person2 = new Person("Person2");
		Stadt stadt = new Stadt("Stadt");
		stadt.addPerson(person1);
		stadt.addPerson(person2);
		savePerson(stadt);
		em.clear();
		showDetails();
		updateStadt(stadt.getId());
		em.clear();
		System.out.println();
		showDetails();
	}
	
	private static void updateStadt(Long id){
		em.getTransaction().begin();
		Stadt stadt = em.find(Stadt.class, id);		
		Person p = stadt.getPersons().get(0);
		stadt.getPersons().remove(p);
		p.setStadt(null);
		em.getTransaction().commit();

	}
	
	private static void savePerson(Object o){
		em.getTransaction().begin();
		em.persist(o);	
		em.getTransaction().commit();	
	}
	
	private static void showDetails() {
		List<Stadt> stadtListe = em.createQuery("select s from Stadt s",Stadt.class).getResultList();
		for(Stadt s : stadtListe){
			System.out.println(s);
		}
		List<Person> personListe = em.createQuery("select p from Person p",Person.class).getResultList();
		for(Person p : personListe){
			System.out.println(p);
		}	
	}
}```

Ausgabe (Die Zahl ist die Versionsnummer):


Stadt: Stadt 1
Person: Person 1
Person: Person2 1

Stadt: Stadt 1
Person: Person2 1
Person: Person 2

Warum möchtest Du das denn? Das Hochzählen der version der Person macht alle konkurrierenden und ungültigen Speicherversuche erkennbar. Genau darum geht es bei dem version-Feld.

Das ist mir schon klar. :slight_smile:
Dabei geht es mir ja auch nicht um die Person, dort ist ja alles korrekt.

Eher um folgendes Szenario:

Zwei Nutzer bearbeiten gleichzeitig in einer Oberfläche zum Beispiel eine Stadt.
Nutzer1 fügt 3 Personen hinzu und Nutzer2 löscht zwei der vorhandenen Personen. Beide speichern.
In dem oben genannten Fall würde das kein Problem darstellen, aber es würde dazu führen, dass beide Nutzer gleichzeitig die Stadt bearbeitet haben, welches in meinen Augen „unerwartete“ Ergebnisse für die Benutzer bringen könnte.

Ich stelle mir hier eher vor, dass nach dem Speichern der geänderten Stadt die Version der Personen UND der Stadt hochgezählt wird, sodass Nutzer2 die Nachricht bekommt, dass die Stadt bearbeitet wurde.

Vielleicht bin ich aber auch mit der Meinung irgendwie auf dem falschen Dampfer, da ich über DIESES Verhalten, also das beide Seiten geändert werden, ziemlich wenig finde :confused:

okay der SPEC is da eindeutig

All non-relationship fields and properties and all relationships owned by the entity are
included in version checks
.

EclipseLink und Hibernate bieten dort optionale Alternativen. OpenJPA mal wieder net :smiley:

JPA Version 1.2.3 hat es zum Beispiel noch so gemacht, dass alle Child und Parent geupdatet werden.

Das mit dem em.lock(stadt, LockModeType.OPTIMISTIC_FORCE_INCREMENT) ist wohl ein Bug.
Damit ist das Thema erledigt und ich hab mir etwas anderes überlegt bzw. meine GUI dazu abgeändert.