I managed to insert crew for my movie - now I want to do it the right way. Entities (abbreviated):
@Entity
@Table(name = "movies")
public class Movie implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int idmovie;
// bi-directional many-to-one association to MoviesHasCrew
@OneToMany(mappedBy = "movy", cascade = CascadeType.PERSIST)
private List<MoviesHasCrew> moviesHasCrews;
}
@Entity
@Table(name = "movies_has_crew")
public class MoviesHasCrew implements Serializable {
@EmbeddedId
@GeneratedValue(strategy = GenerationType.IDENTITY)
private MoviesHasCrewPK id;
// bi-directional many-to-one association to Crew
@ManyToOne
@JoinColumn(name = "crew_idcrew", columnDefinition = "idcrew")
@MapsId("crewIdcrew")
private Crew crew;
// bi-directional many-to-one association to Movy
@ManyToOne
@JoinColumn(name = "movies_idmovie")
@MapsId("moviesIdmovie")
private Movie movy;
// bi-directional many-to-one association to Role
@ManyToOne
@JoinColumn(name = "roles_idrole")
@MapsId("rolesIdrole")
private Role role;
}
@Entity
@Table(name = "crew")
public class Crew implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int idcrew;
// bi-directional many-to-one association to MoviesHasCrew
@OneToMany(mappedBy = "crew", cascade = CascadeType.PERSIST)
private List<MoviesHasCrew> moviesHasCrews;
}
Sorry for 'movy' and 'crews' that's the tools (and qualifies for a bug report)
Controller and form:
@ManagedBean
@ViewScoped
public class MovieController implements Serializable {
@EJB
private MovieService service;
private Crew crewMember;
private Movie movie;
public String addCrewMember() {
if (movie.getIdmovie() == 0) {
movie = (Movie) FacesContext.getCurrentInstance()
.getExternalContext()
.getSessionMap().get("movie");
}
service.addCrew(movie, crewMember);
return null;
}
}
<h:form id="movie_add_crew_form" rendered="#{sessionScope.movie != null}">
<h:panelGrid columns="2">
<h:selectOneListbox id="crewMember" redisplay="true" size="8"
value="#{movieController.crewMember}"
converter="#{movieController$CrewConverter}">
<f:selectItems value="#{movieController.allCrew}" var="entry"
itemValue="#{entry}" itemLabel="#{entry.name}" />
<f:ajax event="blur" render="crewMemberMessage" />
</h:selectOneListbox>
<h:message id="crewMemberMessage" for="crewMember" />
</h:panelGrid>
<h:commandButton value="Add" action="#{movieController.addCrewMember}">
<f:ajax execute="@form" render="@form :movie_crew" />
</h:commandButton></h:form>
And finally the service:
@Stateless
public class MovieService {
@PersistenceContext
private EntityManager em;
public void addCrew(Movie m, Crew w) {
MoviesHasCrew moviesHasCrew = new MoviesHasCrew();
moviesHasCrew.setCrew(w);
moviesHasCrew.setMovy(m);
moviesHasCrew.setRole(Role.DEFAUT_ROLE);
em.persist(moviesHasCrew);
m.addMoviesHasCrew(moviesHasCrew); // (1)
em.merge(m); // noop
}
}
Question 1: I want to have the Crew and Movie entities' fields moviesHasCrews
updated on persisting the MoviesHasCrew
entity (ie drop m.addMoviesHasCrew(moviesHasCrew); em.merge(m);
) but my cascade annotations do not seem to do it. Should I do it the other way round ? That is add to moviesHasCrews
in movies and merge/perist Movie and have the MoviesHasCrew
updated - this I read needs hibernate but I work with generic JPA - is it still not doable in vanilla JPA ?
Question 2: a rundown of how this should be done would be appreciated (for instance should I add fetch=Lazy
(in Movie
and Crew
) @Transient
to the moviesHasCrews
fields ?). Is @MapsId("moviesIdmovie")
etc needed in the join table entity ? Is this the most minimal/elegant way of doing it ?
The schema:
References: