2016-06-13 18 views
1

Ich habe ein Problem, wo ich ein Modell in Ebean aktualisieren, aber andere Verweise auf das Modell werden nicht geändert. Ich habe mich gefragt, ob es möglich ist, automatisch alle Modelle zu aktualisieren oder zu aktualisieren, die auf das aktualisierte Modell verweisen, indem sie verknüpfte Spalten oder @ManyToMany-Zuordnungen verwenden.Wie aktualisiert man alle Referenzen in Ebean ORM

Dies ist mein Testcode:

// Create students and club 
Student john = new Student("John"); 
Student lizz = new Student("Lizz"); 
Club soccer = new Club("Soccer"); 

// Save the students 
server.save(john); 
server.save(lizz); 

// Add them to their club 
john.getClubs().add(soccer); 
server.save(john); 
lizz.getClubs().add(soccer); 
server.save(lizz); 

// Reload users (fresh) 
john = server.find(Student.class).where().ieq("name", "john").findUnique(); 
lizz = server.find(Student.class).where().ieq("name", "lizz").findUnique(); 
System.out.println("Club: " + lizz.getClubs().get(0).getName()); 

// Modify the club name 
john.getClubs().get(0).setName("Baseball"); 
System.out.println("Club: " + lizz.getClubs().get(0).getName()); 

// Update the club 
server.save(john); 
System.out.println("Club: " + lizz.getClubs().get(0).getName()); 

und das sind meine Modelle:

@Entity 
@Table(name = "students") 
public class Student { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(unique = true, updatable = false) 
    private int id; 

    @Column 
    private String name; 

    @ManyToMany(mappedBy = "students", cascade = CascadeType.ALL) 
    private List<Club> clubs; 

    @Version 
    private long version; 
} 

und:

@Entity 
@Table(name = "clubs") 
public class Club { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(unique = true, updatable = false) 
    private int id; 

    @Column 
    private String name; 

    @ManyToMany 
    @JoinColumn 
    private List<Student> students; 

    @Version 
    private long version; 
} 

Der Ausgang der Club ist wie Fußball bleibt, wie so :
Verein: Fußball
Verein: Fußball
Verein: Fußball

+0

Wenn der Code John und Lizz ... neu lädt, da es keinen übergreifenden Transaktion/Persistenzkontext gibt ... das erstellt 2 unabhängige Objektdiagramme. Diese Objektgraphen stellen einen "Schnappschuss eines Teils der Datenbank zu einem bestimmten Zeitpunkt und auf einer bestimmten Isolationsstufe dar (gelesen gemäß der JPA-Spezifikation usw.). –

+0

@RobBygrave das macht Sinn, ich setze die Isolationsstufe auf SERIALIZABLE weil Es unterstützt sowohl SQLite und MySQL, einige andere nicht Ist es möglich, immer die gleiche Referenz zu halten? – lenis0012

+0

Bei SERIALIZABLE Optimistische Parallelitätsprüfung funktioniert nicht (gut, die Überprüfung ist relativ zum Beginn der Transaktion). Im Allgemeinen müssen Sie pessimistisches Sperren bei SERIALIZABLE starten, für eine Anwendung mit hohem Nebenläufigkeit ist das ein Problem, also ist READ_COMMITTED IMO eine viel viel bessere Wahl, es sei denn ... –

Antwort

2

Sie modifizieren John aber Drucken Lizz. Lizz hat sich nicht geändert (insofern wurde der Club für Lizz geladen und es wird nicht aktualisiert).

Der Grund ist, weil der Abruf von John und Lizz in 2 verschiedenen Transaktionen sind und als solche zwei verschiedene Persistenzkontexte haben. Wenn es eine Transaktion gab, die den Abruf von BOTH John und Lizz umfasste, wäre der Club die gleiche/einzige Instanz für beide, da der zugrundeliegende Persistenzkontext auf die Transaktion beschränkt ist und sicherstellt, dass dieselbe Instanz für den Club verwendet wird .

Als Neben Punkt, den Sie beim Einschalten SQL und Transaktionsprotokollierung so aussehen sollte, dass Sie bestätigen, es tut, was Sie denken, es sollte:

<!-- LOGBACK configuration --> 

<!-- SQL and bind values --> 
<logger name="org.avaje.ebean.SQL" level="TRACE"/> 

<!-- Transaction Commit and Rollback events --> 
<logger name="org.avaje.ebean.TXN" level="TRACE"/> 

Für die Protokollierung Konfiguration http://ebean-orm.github.io/docs/setup/logging

beziehen:

server.beginTransaction(); 
try { 
    // persistence context scoped to transaction so 
    // .. now spans both fetches giving John and Lizz 
    // .. the same shared Club instance 
    john = server.find(Student.class).where().ieq("name", "john").findUnique(); 
    lizz = server.find(Student.class).where().ieq("name", "lizz").findUnique(); 
} finally { 
    server.endTransaction(); 
} 
+0

danke das ist sehr hilfreich. In der Praxis würde ich sie jedoch nicht beide gleichzeitig laden. Aber ich möchte den Club für einen Schüler ändern, ohne dass alle Clubs inkonsequent sind. – lenis0012

+0

Siehe die andere Diskussion oben. –

+0

FYI: Es gibt ein Video über den "Persistence Context" von Ebanan unter https://youtu.be/Y18HsBkeLuk ... vergleicht es mit JPA und erklärt hoffentlich ein bisschen mehr, warum das so funktioniert. –