Search code examples
mysqljpaormmany-to-manyeclipselink

JPA, already persisted object gives "a new object was found through a relationship that was not marked cascade PERSIST"


I'm trying to understand why I get an error when persisting a Tournament but not when I'm persisting a Match.

The error:

Caused by: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: main.java.entities.Team@3eff51aa.

Neither Match nor Tournament has the team entity annotated with cascade persist. Yet match is still persisting without error.

So here is how it works : I can create Thethread entity that can be either a Tournament or a Match (not both). When Creating Match or Thethread I load the different Teams from the database and I can select which team participate in what. Such as a Match will have 2 teams in it and a tournament will have teams which are contained in groups (group a, b, c etc.). The only difference I see between those two is that one relationship is @ManyToMany and the other is @ManyToOne. A team has many matches but a match has only one teamA (and one teamB). A tournament has many Groups and a group has many teams, a team has many groups. Notice that in both case team has no CascadeType.Persist (which I don't want since I'm taking them from the DB, persisting those would make duplicates).

Thread

public class Thethread implements Serializable {  
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idthread")
    private long idthread;


    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "categories_idcategory")
    private Category category;


    @OneToOne(mappedBy = "thread", cascade = CascadeType.PERSIST)
    private Match match;

    @OneToOne(mappedBy="thread", cascade = CascadeType.PERSIST)
    private Tournament tournie;

Match

public class Match implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_match")
    private long idmatch;

    @OneToOne
    @JoinColumn(name = "idthread")
    private Thethread thread;

    @NotNull
    @ManyToOne
    @JoinColumn(name = "team_a")
    private Team teamA;

    @NotNull
    @ManyToOne
    @JoinColumn(name = "team_b")
    private Team teamB;

Tournament

@Entity
@Table(name="layout_tournament")
public class Tournament implements Serializable{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idlayout_tournament")
    private int idtournie;


    @OneToMany(mappedBy="tournie", cascade = CascadeType.PERSIST)
    private List<TournamentGroup> groups;

    @OneToOne
    @JoinColumn(name="thread")
    private Thethread thread;
}

TournamentGroup:

public class TournamentGroup implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="idtournie_group")
    private int idgroup;

    @ManyToOne
    @JoinColumn(name="tournie")
    private Tournament tournie;


    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name="team_has_tournie_group",
            joinColumns=
             @JoinColumn(name="tournie_group"),
        inverseJoinColumns=
             @JoinColumn(name="team"))
    private List<Team> teams;
}

When persisting into the DB I do it like so:

    @Override
    public void updateLatestThreadCategory(long id, Thethread latestThread) {
        // Query query = em.createQuery(JPQL_FIND_BY_ID, Category.class);
        // query.setParameter("id", id);
//      if(null != latestThread.getTournie()){
//          if(null != latestThread.getTournie().getGroups()){
//              for (TournamentGroup g : latestThread.getTournie().getGroups()){
//                  for(Team t : g.getTeams()){
//                      t = em.getReference(Team.class, t.getIdteams());
//                  }
//              }
//          }
//      }
        em.persist(latestThread);
        Category cat = em.getReference(Category.class, id);
        cat.setlastThread(latestThread);

The commented part is me trying to let the team be managed but it didn't work.

So I have two questions if someone read till here:

  • Why is it that I can persist a thread containing a match without problem but I'm having an error for a thread containing a tournament.(note that the teams are taken from the DB but in both case I suppose aren't managed )?
  • When I persist a match, which has teamA and teamB: does JPA simply writes the ID of a team in the match table or does it also update the team ? So if someone decides to create a match he first request the teams that appear in a drop down list. In the meantime if the owner of a team decides to edit his team and update it in the DB. Then a match is created, with the unedited teams, the edit will be overwrote right ?

I'm using EclipseLink 2.6


Solution

  • I created another entity to represent the table in between the manytomany association. The error is gone but I changed many things so I can't guarantee it's what solved the issue. As for why this happens I think it's because the team exists in the team table but isn't yet in the table making the manytomany association.