简体   繁体   中英

Implementing Composite (Embedded-ID) Foreign Key Relations using Spring Data JPA

Interestingly, I can't find any solution for a seemingly common scenario! So I'm asking here to learn from experienced professionals in Spring Data JPA . I'll consider using Lombok to make the sample codes more concise.

Consider a simple IMDB example web application. I've defined two simple entities as below:

@Data
@Entity
public class Movie {

    @Id
    @GeneratedValue
    private long id;
    private String title;
    private int year;
    private int rating;
}

@Data
@Entity
public class Actor {
    
    @Id
    @GeneratedValue
    private long id;
    private String firstName;
    private String lastName;
    private Date birthday;
    private String gender;
}

Now we need a join-table to link these two entities; but this is not just a simple join-table. Other than the actor and movie columns, this table has some additional attributes. We didn't want to waste storage by adding an ID column here, instead we used a composite-key consisting of actor and movie :

@Data
@Embeddable
public class MovieActorId implements Serializable {
    
    private Actor actor;
    private Movie movie;
}

@Data
@Entity
public class MovieActor {
    
    @EmbeddedId
    private MovieActorId id;
    private int salary;
    private String characterName;
}

There are two Many-to-One relations here: MovieActor >-- Actor and MovieActor >-- Movie .

Now my main question is: "Assuming the above design, how should I define the @ManyToOne relationships in this design?"

NOTE: I believe if we add an additional ID column to the MovieActor join-table instead of the composite/embedded MovieActorId , the JPA code will become fairly straight-forward. But suppose we have some sort of limitation, and we need to stick to this design as much as possible.

You need to use @MapsId which provides the mapping for an EmbeddedId primary key in @ManyToOne relation

@Data
@Embeddable
public class MovieActorId implements Serializable {
    
    private long actorId;
    private long movieId; 

    // constructor, setter, etc
}

@Data
@Entity
public class MovieActor {
    
    @EmbeddedId
    private MovieActorId id;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("actorId")
    private Actor actor;
    
    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("movieId")
    private Movie movie;
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM