# Problem mit @ManyToMany und CascadeType.ALL



## bluer (8. Aug 2011)

Hi Leute,

in meiner Web-App soll es möglich, dass ein Berater(Consultant) Kunden (Customer) und Projekte(Project) anlegen kann. Es gibt bei der Web-App ein User-Managment und zwar so, dass ein User entweder ein Berater ist oder ein Kunde. Zwischen der Entity User und Project ist folgende m:n-Beziehung gemappt:

```
...
    @ManyToMany( cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
    @JoinTable( name = "User_Project",
                     joinColumns = {@JoinColumn( name="user_id")},
                     inverseJoinColumns = {@JoinColumn (name = "project_id")})
    public List<Project> getProjects() {return this.projects; }
...
```
Mein Problem ist nun, dass ich bei 2 Usern die Projekte updaten muss und er sowohl beim ersten User als auch beim zweiten das neue Projekt in die DB schreibt bzw. schreiben will. Das ist natürlich nicht gewünscht. Vllt ist meine vorgehensweise nicht korrekt? Ich update bzw. persistiere zu erst den CustomerUser und anschließend den ConsultantUser. Der JavaCode sieht wie folgt aus:
ProjectWizardController.java:

```
...
    @Transactional
    public void finalWizard(){
        if( !this.selectedCatalog.equals(-1L))
            try{
                if( this.customer.getId() == null ){
                    this.user.setPassword(this.password);
                    this.user.addProject(project);
                    Map<String, GrantedAuthority> authorities = new LinkedHashMap<String, GrantedAuthority>();
                    this.messageController = new MessageController();
                    authorities.put(messageController.getMessage("user_role_"
                         + Role.valueOf("CUSTOMER").toString()), new GrantedAuthorityImpl(Role.valueOf("CUSTOMER").toString()));
                    this.user.setAuthorities(authorities.values());
                    User consultantUser = this.userDao.getById(this.consultant.getUser().getId());
                    consultantUser.getProjects().add(this.project);
                    this.userDao.persist(this.user, this.customer, consultantUser);
                    //this.userDao.update(consultantUser, this.project);
                }else{
                    User updateCustomer = this.userDao.getById(this.customer.getUser().getId());
                    updateCustomer.getProjects().add(this.project);
                    User updateConsultant = this.userDao.getById(this.consultant.getUser().getId());
                    updateConsultant.getProjects().add(this.project);
                    this.userDao.update(updateCustomer, updateConsultant);
                }
                this.increasePosition();
                //this.userDao.update(this.customer.getUser(), this.project);
            }catch(Exception e){
                System.out.println(e.getMessage());
            }
    }
...
```
UserDaoImpl:

```
...
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;
...
    public User update(User customer,User consultant){
            em.merge(customer);
            em.merge(consultant);
            em.flush();
            return consultant;
        }

    public void persist(User user, Customer customer, User consultant ){
            em.persist(customer);
            em.persist(user);
            em.merge(consultant);
            em.flush();
        }
...
```
Er versucht immer ein Project doppelt einzutragen. Wie kann ich das verhindern?


----------



## nillehammer (8. Aug 2011)

Zwei Stellen:
1. Implementiere eine equals()-Methode, mit der JAVA erkennt, dass zwei Project-Instanzen gleich sind.
2. In der Project-Entity definiere für die Kombination aus Spalten, die für ein Project einzigartig sein müssen, einen Unique-Constraint. Wenn Du Hibernate benutzt, kannst Du auch NaturalId benutzen


----------



## bluer (8. Aug 2011)

Die ProjectName-Spalte ist schon unique:

```
...
    @Column(unique = true)
    public String getProjectName() {
	return projectName;
    }
...
```
Deswegen schmeißt er mir ja die Exception, dass der Projektname schon vorhanden ist. Gibt es keine Mehtode die sowas sagt wie: Schreibe Daten nur in DB, wenn sie nicht schon existieren?! Mein Problem ist, dass er zuerst beim persistieren bzw. updaten des CustomerUser das Projekt in die DB schreibt, wg CascadeType.ALL, und anschließend das gleiche für den ConsultantUser probiert ... :bahnhof:


----------



## bluer (9. Aug 2011)

Habe das Problem heut morgen gelöst. Sehr hilfreich dabei, war folgende Seite: Java Persistence/ManyToMany - Wikibooks, open books for an open world :toll:
Da steht kurz geagt, dass JPA nicht zaubern kann. D.h. in meinem Fall, einer bidirektionalen m:n-Beziehung, dass man JPA schon mitteilen muss, wann was gelöscht oder hinzugefügt werden soll und es nicht reicht ein CascadeType.ALL anzufügen. DIe Lösung sieht wie folgt aus:

```
public class ProjectWizardController{ 
...
    public void finalWizard(){
    ...
        this.userDao.update(customerUser, consultantUser, project);
    ...
    }
...
}

public class UserDaoImpl implements Userdao{
...
    public User update(User customerUser, User consultantUser, Project project){
        em.persist(project);
        em.merge(customerUser);
        consultantUser = em.merge(consultantUser);
        em.flush();
        return consultantUser;
    }
...
}
```

Vielen Dnak für eure Hilfe!


----------

