Spring JPA:含List属性的Movie实体数据库设计与save方法使用
Hey there! Let's tackle your questions about designing your movie database with Spring JPA and using the save() method effectively. I'll walk through each question with explanations and practical code examples.
1. Should I create separate Movie and Genre tables with a relationship?
Absolutely—this is the standard, database-normalized approach for handling many-to-many relationships (a movie can have multiple genres, and a genre can belong to multiple movies). Here's why it's the right choice:
- Maintains data consistency (no duplicate genre strings scattered across movie entries)
- Enables efficient, targeted queries (e.g., "find all movies in the 'Action' genre")
- Makes updating genre names trivial (no need to edit every movie that uses the genre)
Example Entity Classes
First, create the Genre entity to represent distinct genre records:
package com.kurshit.moviesmgr.vo; import jakarta.persistence.*; import java.util.List; @Entity @Table(name = "genres") public class Genre { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true, nullable = false) private String name; @ManyToMany(mappedBy = "genres") private List<Movie> movies; // Constructors, getters, setters public Genre() {} public Genre(String name) { this.name = name; } // Getters and setters omitted for brevity }
Then update the Movie entity to define the many-to-many relationship:
package com.kurshit.moviesmgr.vo; import jakarta.persistence.*; import java.util.List; @Entity @Table(name = "movies") public class Movie { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long movieId; @Column(nullable = false) private String title; @Column(name = "year_of_release") private String yearOfRelease; @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable( name = "movie_genre", joinColumns = @JoinColumn(name = "movie_id"), inverseJoinColumns = @JoinColumn(name = "genre_id") ) private List<Genre> genres; // Constructors, getters, setters public Movie() {} public Movie(String title, String yearOfRelease, List<Genre> genres) { this.title = title; this.yearOfRelease = yearOfRelease; this.genres = genres; } // Getters and setters omitted for brevity }
2. Can I store all genres as CSV in a single column?
Technically yes, but this is strongly discouraged for most production use cases. Here's the tradeoff:
Pros
- Simpler table structure (only one
moviestable)
Cons
- No efficient way to query by genre (you'd have to use slow, error-prone
LIKEqueries) - Duplicate genre data across movies (e.g., "Action" stored hundreds of times)
- Updating a genre name requires editing every movie entry that uses it
If you still need this approach (e.g., for a small, low-traffic app), you can use a JPA converter to map the List<String> to a CSV string:
package com.kurshit.moviesmgr.converters; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Converter(autoApply = true) public class GenreListConverter implements AttributeConverter<List<String>, String> { private static final String SEPARATOR = ","; @Override public String convertToDatabaseColumn(List<String> genres) { return genres != null ? String.join(SEPARATOR, genres) : null; } @Override public List<String> convertToEntityAttribute(String dbData) { return dbData != null ? Arrays.stream(dbData.split(SEPARATOR)).collect(Collectors.toList()) : List.of(); } }
Then update your Movie entity to use this converter:
@Entity @Table(name = "movies") public class Movie { // ... other fields ... @Column(name = "genres") @Convert(converter = GenreListConverter.class) private List<String> genres; // ... constructors, getters, setters ... }
3. Can I use the repository's save() method directly?
Yes! Once your entities are properly annotated (either for the normalized many-to-many setup or the CSV converter approach), Spring JPA's JpaRepository will handle all mapping and storage logic automatically.
Example Repository Interface
package com.kurshit.moviesmgr.repositories; import com.kurshit.moviesmgr.vo.Movie; import org.springframework.data.jpa.repository.JpaRepository; public interface MovieRepository extends JpaRepository<Movie, Long> { // Add custom query methods here if needed, e.g.: // List<Movie> findByGenresName(String genreName); }
Usage Example
// In a service or controller class @Autowired private MovieRepository movieRepository; public void saveSampleMovies() { // For the normalized many-to-many approach: Genre action = new Genre("Action"); Genre comedy = new Genre("Comedy"); Movie avengers = new Movie("The Avengers", "2012", List.of(action, comedy)); movieRepository.save(avengers); // For the CSV approach: Movie deadpool = new Movie("Deadpool", "2016", List.of("Action", "Comedy")); movieRepository.save(deadpool); }
内容的提问来源于stack exchange,提问作者Kurshit

