2013-04-11 6 views
12

Stellen Sie sich die folgenden Modelle:Wie speichert man eine neue Entität, die eine vorhandene Entität in Spring JPA verweist?

Mitarbeiter:

@ManyToMany(cascade = CascadeType.ALL) 
@JoinTable(name = "employee_project", joinColumns = @JoinColumn(name = "Emp_Id"), inverseJoinColumns = @JoinColumn(name = "Proj_id")) 
private Set<Project> projects = new HashSet<Project>(); 

Projekt:

@ManyToMany(mappedBy = "projects") 
private Set<Employee> employees = new HashSet<Employee>(); 

Nun, wenn ich einen neuen Mitarbeiter schaffen, die zu einem bestehenden Projekt bezieht und versuchen, diese Mitarbeiter zu beharren, ich Fehler erhalten:

detached entity passed to persist: Project 

Ich erstelle den Mitarbeiter Yee wie folgt:

public void createNewEmployee(EmployeeDTO empDTO) { 

    Employee emp = new Employee(); 
    // add stuff from DTO, including projects 

    repository.saveAndFlush(emp); // FAILS 
} 

und ich so bestehende aktualisieren:

public void updateEmployee(EmployeeDTO empDTO) { 

    Employee emp = repository.findOne(empDTO.getId()); 
    // set stuff from DTO, including projects 

    repository.saveAndFlush(emp); // WORKS! 
} 

Antwort

19

Ich denke, Sie mit dem Repository sind die Interaktion in geeigneter Weise die Transaktionsgrenzen ohne Erweiterung. Standardmäßig befindet sich die Transaktion (und damit die Sitzung) auf der Ebene der Repository-Methode. Dies bewirkt, dass die Project Instanz von der EntityManager getrennt wird, so dass sie nicht in eine persistente Operation eingeschlossen werden kann.

Die Lösung hier ist die Transaktionsgrenze an den Client zu erweitern:

@Component 
class YourRepositoryClient { 

    private final ProjectRepository projects; 
    private final EmployeeRepository employees; 

    // … constructor for autowiring 

    @Transactional 
    public void doSomething() { 
    Project project = projects.findOne(1L); 
    Employee employee = employees.save(new Employee(project)); 
    } 
} 

Dieser Ansatz bewirkt, dass die Project Instanz eine verwaltete Einheit bleiben und damit die bestehen bleiben Betrieb für die frische Employee Instanz korrekt behandelt ausgeführt werden wird, .

Der Unterschied zu den beiden Repository-Interaktionen besteht darin, dass Sie im zweiten Fall eine getrennte Instanz haben (wurde bereits persistiert, hat einen ID-Satz), wo Sie wie im ersten Beispiel eine vollständig nicht verwaltete Instanz haben habe keine ID gesetzt. Die ID-Eigenschaft bewirkt, dass das Repository zwischen dem Aufruf von persist(…) und merge(…) unterscheidet. Der erste Ansatz bewirkt also, dass ein persist(…) ausgelöst wird, der zweite verursacht einen merge(…).

+0

Danke, das funktioniert, aber ich möchte immer noch wissen, warum meine Update-Methode funktioniert, ohne die Projekte aus ihrem Repository zu holen (siehe meine aktualisierte Frage für Details) – wannabeartist

+1

Es ist keine gute Idee, Fragen hier zu erweitern, da sie die ungültig machen Antwort zu einem gewissen Grad. Besser neue Fragen stellen. Ich werde meine Antwort entsprechend aktualisieren. –

+0

Ist der Frühling ''Transactional' oder JPA's, oder spielt es eine Rolle? – CorayThan

Verwandte Themen