0

I am trying to build a structure as shown below:

User:

id   | username  |
------------------
1    | Mary      |
2    | George    |
3    | Candy     |
Movie:

id   | name                |
----------------------------
1    | Slumdog Millionaire |
2    | Avatar              |
3    | Star Trek           |
Rating:

user_id   | movie_id  | rate |
------------------------------
1         | 1         |   6  |
2         | 3         |   8  |
3         | 2         |   9  |

A user can only rate the same movie once. I think I should make user_id - movie_id pairs in the rating table Primary Key.

And use one-to many relationships between user - rating and movie - rating entities. Is that true?

I have not enough experience for Hibernate and the examples are generally shows default one-to many relationships. But I think I need a composite key relationship. So, is there an example for this scenario? I searched many of them but I need to find the correct approach and follow it. Thanks in advance.

Update: By using @Embeddedable I updated related entities as shown below:

User:

@Entity
@Table(name = "user")
public class User {

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

    private String username;

    private String password;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Rating> ratings = new HashSet<>();

    public void addRating(Rating rating) {
        ratings.add(rating);
    }

    public void removeRating(Rating rating) {
        ratings.remove(rating);
    }

    // Getters, setters, constructors and equals methods
}

Movie:

@Entity
@Table(name = "movie")
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    
    @OneToMany(mappedBy = "movie", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Rating> ratings = new HashSet<>();
    
    public void addRating(Rating rating) {
        ratings.add(rating);
    }

    public void removeRating(Rating rating) {
        ratings.remove(rating);
    }
    
    // ...
}

@Entity
@Table(name = "rating")
public class Rating {

    @EmbeddedId
    private RatingId ratingId;
    
    private int rate;

    @ManyToOne(fetch = FetchType.LAZY)
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    private Movie movie;
}

RatingId:

@Embeddable
public class RatingId implements Serializable {

    private Long userId;

    private Long movieId;
    
    // ...
}
Jack
  • 1
  • 21
  • 118
  • 236
  • 1
    There might be conflicting behavior because the same column is referenced by two POJO properties, and both cause an update of the entry. Only one should cause a write access, the others should be read-only. Maybe I'm wrong, but calling `setRatingId` and `setUser` at the same time with different values for `RatingId.userId` and `User.id` should cause problems because of the missing `@JoinColumn(insertable = false, updatable = false)` annotation. See [here](https://stackoverflow.com/questions/3669883/hibernate-where-do-insertable-false-updatable-false-belong-in-composite-pr) for details. – 0x1C1B Nov 07 '22 at 16:04
  • Thanks a lot, I fixed the problem using `@JoinColumn(name="movie_id", referencedColumnName="id", insertable = false, updatable = false)` – Jack Nov 07 '22 at 16:16
  • @0x1C1B What about the Entity definitions? Are they correct? SHould I add some annotations for constraint, foreign key and maybe indexes? Could you check please? – Jack Nov 07 '22 at 16:17
  • I'm sorry but the [SO](https://stackoverflow.com) comment section isn't intended for answering further questions or doing code reviews... If you're requesting a code review, please use [Code Review](https://codereview.stackexchange.com/) – 0x1C1B Nov 07 '22 at 16:29
  • @0x1C1B That forum was generally full of homeworks and it would only takes - minutes such a kind of experienced user. – Jack Nov 07 '22 at 17:06

1 Answers1

0

A user can only rate the same movie once. I think I should make user_id - movie_id pairs in the rating table Primary Key.

Yes you are right. You need them as primary key

And use one-to many relationships between user - rating and movie - rating entities. Is that true?

Yes that's correct.

So, is there an example for this scenario?

You can use @IdClass or @EmbeddedId. You can find example and differences between them at: https://www.baeldung.com/jpa-composite-primary-keys

Devanshu
  • 35
  • 1
  • 11
  • Thanks a lot for help, could you have a look at my implementations on Update section? Is it correct based on this scenario? Do I need constraint annotation, etc for my entity definitions? – Jack Nov 07 '22 at 12:58
  • It gives Table [rating] contains physical column name [movie_id] referred to by multiple logical column names – Jack Nov 07 '22 at 13:10