I've created an API that has actor, movie and category entities. Actor and movie are connected by many-to-many relationship that maps to a join table called movie_actor and category is connected with movie by one-to-many relationship.
I'm trying to write a native query that returns an integer that would represent the amount of movies from a specific category where specific actor has played so for example query would return 2 if actor played in 2 different sci-fi movies. I have no problem doing that from the database level where I can see the join table movie_actor but that table remains unaccessible in my api because it's not a separate entity. How can I create it that it automatically maps actor and movie ids as the movie_actor table ?
Here is an example code that works for me in the H2 Database:
SELECT COUNT(*) FROM MOVIE M JOIN MOVIE_ACTOR MA on M.MOVIE_ID = MA.MOVIE_ID WHERE ACTOR_ID = 1 AND CATEGORY_ID = 1
Here are my entities:
Actor:
#Entity
#Data
#Table(name = "actor")
#AllArgsConstructor
#NoArgsConstructor
public class Actor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private long actorId;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Nullable
#ManyToMany(mappedBy = "actors", fetch = FetchType.EAGER)
#JsonBackReference
private List<Movie> movies = new ArrayList<>();
public Actor(String name, String surname){
this.name = name;
this.surname = surname;
}
}
Movie:
#Entity
#Data
#Table(name = "movie")
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private long movieId;
#Column(name = "title")
private String title;
#ManyToMany
#JoinTable(
name = "movie_actor",
joinColumns = #JoinColumn(name = "movie_id"),
inverseJoinColumns = {#JoinColumn(name = "actor_id")}
)
#JsonManagedReference
private List<Actor> actors = new ArrayList<>();
#ManyToOne
#JoinColumn(name = "CATEGORY_ID")
#JsonManagedReference
private Category category;
}
So you have to make it accessible in your API. One option would be to map the intersection table movie_actor to the entity MovieActor and split ManyToMany relationship between Actor and Movie to OneToMany relationship with MovieActor, like that:
#Entity
#Data
#Table(name = "movie_actor")
#AllArgsConstructor
#NoArgsConstructor
public class MovieActor {
#EmbeddedId
private MovieActorId productOrderId = new MovieActorId();
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#MapsId("movieId")
#JoinColumn(name = "product_id", nullable = false)
private Movie movie;
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#MapsId("actorId")
#JoinColumn(name = "order_id", nullable = false)
private Actor actor;
public void addMovieActor(Movie aMovie, Actor aActor) {
movie = aMovie;
actor = aActor;
aMovie.getMovieActors().add(this);
aActor.getMovieActors().add(this);
}
}
#Embeddable
#Getter
#Setter
public class MovieActorId implements Serializable {
#Column(name = "movie_id")
private Long movieId;
#Column(name = "actor_id")
private Long actorId;
}
#Entity
#Data
#Table(name = "actor")
#AllArgsConstructor
#NoArgsConstructor
public class Actor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private long actorId;
#OneToMany(mappedBy = "actor")
private List<MovieActor> movieActors = new ArrayList<>();
}
#Entity
#Data
#Table(name = "movie")
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private long movieId;
#OneToMany(mappedBy = "movie")
private List<MovieActor> movieActors = new ArrayList<>();
}
Now you can access the intersection table MovieActor inside the query. You can even add more columns to this table if you want.
Related
This inserts the parent (vehicle) but doesn't insert anything into the child table. I'm new to hibernate, is there something wrong here or is my problem elsewhere?
#Entity
#Table(schema = "mydb", name = "vehicles")
#Data
public class Vehicles {
#Id
#Column(name = "idvehicle")
private Long idVehicle;
#Column(name = "color")
private String color;
#Column(name = "passengers")
private Double passengers;
// field idcar (fk) must have the idcar field (pk) of the child
#OneToOne(cascade= CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#JoinColumn(name = "idcar", columnDefinition = "serial")
private Car car;
}
#Entity
#Table(schema = "mydb", name = "cars")
#Data
public class Cars {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idcar", columnDefinition = "serial")
private Long idCar;
#Column(name = "owner")
private String owner;
}
I'm getting this a BeanCreationException and I think it's because of my hibernate mappings.
I've been trying to figure out what mapping is wrong but no luck so far!
Customer class :
#Entity
#Data
#Table(name = "customer")
public class Customer {
#Id
#Column(name = "registration_code")
private String registrationCode;
private String name;
private String email;
private String phoneNumber;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer", cascade = {CascadeType.MERGE, CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST})
private List<Order> orders;
}
Order class:
#Data
#Entity
#Table(name = "order")
public class Order {
#ManyToOne
#JoinColumn(name = "customer_code")
private Customer customer;
#Id
#OneToMany
#JoinColumn(name = "order_line_id")
private List<OrderLine> orderLines;
#Column(name = "date",columnDefinition = "DATE")
private LocalDate dateOfSubmission;
}
OrderLine class:
#Data
#Entity
#Table(name = "order_line")
public class OrderLine {
#Id
#Column(name = "order_line_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToOne
#JoinColumn(name = "product_code")
private Product product;
private Integer quantity;
}
Product class:
#Data
#Entity
#Table(name = "product")
public class Product {
#Id
private String skuCode;
private String name;
private Long price;
}
It's a spring boot application and I'm using Spring Data JPA
I have two tables. A Users table and an Artists table. Users can be associate with many artists, and vice versa. I have an API call that adds an Artist to the User's list. The API seems to work correctly, but when I check the User afterward, my postman return shows an endless list of the artist I added.
The user entity:
#Entity
#Table(name = "users")
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Slf4j
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
Integer id;
#Column(name = "username")
String username;
#Column(name = "picture_link")
String pictureLink;
#ManyToMany
#JoinTable(
name = "user_artist",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "artist_id"))
Set<Artist> artists = new HashSet<>();
The artist entity:
#Entity
#Table(name = "artists")
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Slf4j
public class Artist {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
Integer id;
#Column(name = "name")
String name;
#Column(name = "description")
String description;
#Column(name = "picture_link")
String pictureLink;
#Column(name = "genres")
String genres;
#ManyToMany(mappedBy = "artists")
Set<User> users = new HashSet<>();
#Transient
List<Album> albums = new ArrayList<>();
}
The api call that causes the infinite loop:
#Override
public String addArtistToFaveList(int user_id, int artist_id) {
try{
User foundUser = new User();
Artist foundArtist = new Artist();
Optional<User> resultUser = userRepo.findById(user_id);
Optional<Artist> resultArtist = artistRepo.findById(artist_id);
if(resultUser.isPresent() && resultArtist.isPresent()){
foundUser = resultUser.get();
foundArtist = resultArtist.get();
}
Set<Artist> userFaveSet = foundUser.getArtists();
userFaveSet.add(foundArtist);
userRepo.save(foundUser);
return "THIS WORKED!";
}catch(Exception e){
return "Failed completely.";
}
}
I have question. I have 3 entities Book->Part->Page with relationships.
Book.java
#Entity
#Table(name = "Book")
public class Book{
#ID
#Column(name = "id")
private Long id;
#OneToMany
#JoinColumn(name="bookid", referencedColumnName="id")
private Set<Part> parts = new HashSet<Part>;
}
Part.java
#Entity
#Table(name = "Part")
public class Part{
#ID
#Column(name = "id")
private Long id;
#Column(name="bookid")
private Long bookid;
#ManyToMany
#JoinTable(name="partpage",
joinColumns = #JoinColumn(name = "id")
inverseJoinColumns = #JoinColumn(name = "pageid")
private Set<Page> pages = new HashSet<Page>;
}
Page.java
#Entity
#Table(name = "Page")
public class part{
#ID
#Column(name = "pageid")
private Long id;
#Column(name="color")
private String color;
#Column(name="type")
private String type;
}
I have query = "Select b FROM book b". This query returns all books with all relation parts and pages.
What I need.
I need count how many pages with color = green and type = comedy in each Book. Is it possible to do it in one query?
Thank you all.
I am trying to develop a system for managing dormitories. Since I don't have much experience with databases, I am stuck on a problem and I have a solution but I am not sure if this would be the right approach.
So I have Room and User. Each user can be accommodated in one room, but one room can accommodate more users. I would like to manage this relationship in one entity - Accommodation. Here I would have more properties, like start/end Date, etc.
I am using Hibernate to map the tables. From what I've read, persisting Collections from Java can be done in two ways, either by #OneToMany or by #ElementCollection. I am not quite sure if I should define this relationship in the Room entity or in the Accommodation entity? If I do it in the room entity then the Accommodation would hold just fk from the room/user tables?
Also, is it possible to only fetch the primary key when doing one-to-many relations instead of getting the whole object? I know that FETCH.LAZY does this, but in my Accommodation entity ideally I would want to store only Set studentsIds.
Thank you in advance.
#Table(name = "student")
#AllArgsConstructor
#Data
#Embeddable
#NoArgsConstructor
#javax.persistence.Entity
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "role")
private String role;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "room", nullable = false)
private Room room_number;
}
Here is the Room entity
#javax.persistence.Entity
#Table(name = "room")
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Data
public class Room
{
#Id
#Column(name = "room_number")
private Long roomNumber;
#Column(name = "location_address")
private String locationAddress;
#Column(name = "dormitory_name")
private String dormitoryName;
}
Accommodation entity
#javax.persistence.Entity
#Table(name = "accommodation")
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Data
public class Accommodation extends Entity {
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "room_number")
private Room room_number;
#OneToMany(mappedBy = "room_number", // I am not sure about this
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true) private List<Student> students;
#Column(name = "date_from")
private Date dateFrom;
#Column(name = "date_to")
private Date dateTo;
}