6

I have two entities: Actor and Movie. Between these two exists a ManyToMany relationship (because and Actor can join more than one Movie and in a Movie you can see more than one Actor). On my Spring Data Rest API I have the following endpoints:

http://host:port/movies
http://host:port/actors

Now suppose I would create a new actor from the movie page. My client will submit a (single) POST request with the actor information and the relationship with the movie. I tried with something like the following (a new actor for the movie with id 1):

{ 
  "name": "Leonardo Di Caprio",
  "movies": [ "http://host:port/movies/1" ]
}

Spring API replies with a 201 Created, so the format and the movie URI are fine. When I query API or DB for the actor, I discover that the actor has been created but the relationship does not exists.

I already know that you should make two requests ( one to create the actor and one to create the relationship ) for ManyToMany relationships with Spring data rest. I'm asking here if there is a way to create both with a single request (like for OneToMany/ManyToOne or OneToOne relationships.

Actor class

@Entity
public class Actor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String name;

    @ManyToMany(mappedBy = "actors")
    private List<Movie> movies;

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Movie> getMovies() {
        return movies;
    }

    public void setMovies(List<Movie> movies) {
        this.movies = movies;
    }
}

Movie Class

@Entity
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected long id;

    protected String title;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
    protected List<Actor> actors;

    public long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<Actor> getActors() {
        return actors;
    }

    public void setActors(List<Actor> actors) {
        this.actors = actors;
    }

}

For both entities, I have standard repositories:

@Repository
public interface ActorRepository extends PagingAndSortingRepository<Actor, Long> {
}

UPDATE

The behaviour that I was facing was due to how JPA handles ManyToMany relationships. In this thread there is a clever explanation on how to handle bidirectional associations with JPA and REST.

I can solve my problem with one of these two options:

A - Doing two POST requests, one on

http://host:port/actors 

to persist the new Actor and one on the

http://host:port/movies/{id}/actors 

as the following:

...                                              |
Content-Type: text/uri-list                      | headers
...                                              |

http://host:port/actors/{id-of-the-new-actor}    | body

to persist the association between the new actor and the movie.

B - Doing only one POST request on

http://host:port/actors 

(as I described at the beginning of the question) but modifying the setMovies method in the Actor class (as described in the thread I cited).

Community
  • 1
  • 1
Francesco
  • 321
  • 3
  • 10
  • Seems like an odd way to post the associated movies. What's the method method in your rest controller look like? – ChiefTwoPencils Aug 20 '16 at 18:36
  • I'm going to post only one associated movie. On the movie page you can add actors for the movie you are viewing, so I thought that doing only one request was the best way. Tell me whether to send two requests (one for the new Actor and one for the new relationship between Movie and Actor) would be a better choice. – Francesco Aug 21 '16 at 01:51
  • A nice question that's left unanswered :/ – EralpB Mar 15 '17 at 10:06
  • Where is code for setMovies method,what line of code should be changed – Taimur Mar 29 '17 at 14:16

1 Answers1

1

First create the resources : create the actor resource :

curl -i -X POST -H "Content-Type:application/json"
    -d "{\"name\":\"Leonardo Di Caprio\"}" http://host:port/actors

then create the movies :

curl -i -X POST -H "Content-Type:application/json"
  -d "{\"title\":\"Titanic\"}" http://host:port/movies

finaly create the association (supposing http://host:port/actors/1 is dicaprio uri):

curl -i -X PUT -H "Content-Type:text/uri-list"
  --data-binary @movies.txt http://host:port/actors/1/movies

with movies.txt containing the movie's uris, each on a separate line:

http://host:por/movies/1
http://host:por/movies/2

follow this useful link

naydnabil
  • 11
  • 4