Creating One to Many relation in JPA Spring - spring

I would like to link a comment table and a film table with a user table. I wish to allow a user to have many comments, and a film have many comments. I then want to display a list of comments in a details page for each film, giving the option for the user who created the comment to delete or update it.
I altered my code in an attempt to create a one to many relation between comment and film, but I get the error:
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column
"FILM_ID"; SQL statement: alter table film add column film_id bigint
not null [23502-196]
It makes me think two things:
1) Set to allow null or figure out why there is a null field. I attempted allow null by adding #Column(name = "film_id", nullable = true) but it said parameter is redundant.
2) Film table has auto incrementing ID already, so by adding #Column(name = "film_id") am I duplicating an ID? As with the error message saying "add column" it made me think so?
My attempt currently stands at:
Film.java
package com.demo.spring.domain;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
#Entity
public class Film {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "film_id", nullable = true)
Long id;
String title;
String director;
String description;
#DateTimeFormat(pattern="yyyy-MM-dd")
Date date;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "film_id", referencedColumnName = "film_id")
List<Comment> comments;
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
//rest of getter and setters below//
Comment.java
package com.demo.spring.domain;
import javax.persistence.*;
#Entity
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "comment_id")
Long id;
String body;
#Column(name = "film_id")
Long filmId;
public Long getFilmId() {
return filmId;
}
public void setFilmId(Long filmId) {
this.filmId = filmId;
}
public Comment(){
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
UPDATE
I have changed Film.java..
From:
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "film_id", referencedColumnName = "film_id")
List<Comment> comments;
To:
#OneToMany(cascade = CascadeType.ALL)
List<Comment> comments;
And if I add in Comment.java:
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="film", joinColumns=#JoinColumn(name = "film_id_fk", referencedColumnName = "film_id"))
private Set<Comment> comment = new HashSet<Comment>();
Film film;
I get:
MappingException: Foreign key
(FK5vk85sy54a8be115ye9ra1lyu:film_comments [film_film_id])) must have
same number of columns as the referenced primary key (film
[film_id_fk,comment_comment_id])
If I change private Set<Comment> comment = new HashSet<Comment>(); to List<Comment> comments = new ArrayList<Comment>(); I get:
NULL not allowed for column "FILM_ID"; SQL statement: alter table film
add column film_id bigint not null
And if instead I add:
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name = "film_id_fk", referencedColumnName = "film_id")
private Set<Comment> comment = new HashSet<Comment>();
Film film;
I get:
MappingException: Could not determine type for:
com.demo.spring.domain.Film, at table: comment, for columns:
[org.hibernate.mapping.Column(film)]
If I change private Set<Comment> comment = new HashSet<Comment>(); to List<Comment> comments = new ArrayList<Comment>(); I get:
NULL not allowed for column "FILM_ID"; SQL statement: alter table film
add column film_id bigint not null

A primary key can't be null, so you can't make "film_id" nullable. And your #JoinColumn annotation is wrong, that goes on the #ManyToOne side. The name parameter should be the name of the foreign key column in the Comments table (so it can't be the same name as the primary key) and referencedColumnName should be the name of the column that you're referencing in the other table
#Entity
public class Film {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "film_id")
Long id;
String title;
String director;
String description;
#DateTimeFormat(pattern="yyyy-MM-dd")
Date date;
#OneToMany(cascade = CascadeType.ALL)
List<Comment> comments;
//...
}
#Entity
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "comment_id")
Long id;
String body;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "film_id_fk", referencedColumnName = "film_id")
Film film;
//...
}

Related

update or delete on table "sessions" violates foreign key constraint "session_schedule_session_id_fkey"

I have to entities modeled Session and Speaker, with ManyToMany relationship, and I wanted to delete an instance of Session, but in the DB it is the foreign key of another table. Below is the entity model
#Entity(name = "sessions")
public class Session {
// attributes do not respect camel case notations because they
// need to match table notations in order to auto bind without annotations
// otherwise that is done with #Column annotation
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long session_id;
private String session_name;
private String session_description;
private String session_length;
#OnDelete(action = OnDeleteAction.CASCADE)
#ManyToMany()
#JoinTable(
name = "session_speakers",
joinColumns = #JoinColumn(name = "session_id"),
inverseJoinColumns = #JoinColumn(name = "speaker_id")
)
private List<Speaker> speakers;
public Session() {
}
I tried to use OnDelete Cascade, but it still didn't work. (I did read that it is not advised to use on ManyToMany relationship)
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void delete(#PathVariable Long id){
sessionRepo.deleteById(id);
}
EDIT:
here is also the Speaker entity
#Entity(name = "speakers")
public class Speaker {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long speaker_id;
private String first_name;
private String last_name;
private String title;
private String company;
private String speaker_bio;
#Lob
#Type(type = "org.hibernate.type.BinaryType")
private Byte[] speaker_photo;
public Byte[] getSpeaker_photo() {
return speaker_photo;
}
public void setSpeaker_photo(Byte[] speaker_photo) {
this.speaker_photo = speaker_photo;
}
#ManyToMany(mappedBy = "speakers")
#JsonIgnore// added to resolve serialization issues
private List<Session> sessions;

how to add object with fk to table in jparepository

i had scheme of user parking and detail parking.
user can park many times (one to many)
im trying to add detail parking object to my db, but i dont have idea how to add the fk from the user in the row of the table, its gave me null there.
(ignore from the logic of the model, i just want to understood the logic how can i the object with fk of ther entity)
this is my code:
#PostMapping("/parking")
public String saveCarParking(#ModelAttribute("user") parkingUsers parkingUsers) {
// parkingUsers[id, firstName, lastName, license]
parkingUsers p = new parkingUsers("jhon", "nash", "248651355");
parkingUsersService.saveParkingUser(p);
// parkingDetails[id, entryDate, entryTime, exitDate, exitTime, user_id(FK)]
parkingDetails d = new parkingDetails(LocalDate.now(), null, LocalDate.now(), null);
parkingDetailsService.saveParkingUser(d);
//how i connect parkingDetails object with fk of parkingUsers?
//it adding now row of parkingDetails but without the fk of user
return "redirect:/parkingList";
}
parking user entity:
#Entity
#Table(name ="users")
public class parkingUsers {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "license")
private String license;
#OneToMany(mappedBy = "parkingUsers", cascade = CascadeType.ALL, orphanRemoval = true)
private List<parkingDetails> parkingDetails = new ArrayList<parkingDetails>();
public parkingUsers() {
}
public parkingUsers(String firstName, String lastName, String license) {
this.firstName = firstName;
this.lastName = lastName;
this.license = license;
}
//setter gettrs and tostring...
entity class of details parking
#Entity
#Table(name ="details")
public class parkingDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "entry_date")
private LocalDate entryDate;
#Column(name = "entry_time")
private LocalDateTime entryTime;
#Column(name = "exit_date")
private LocalDate exitDate;
#Column(name = "exit_time")
private LocalDateTime exitTime;
#ManyToOne
#JoinColumn(name="user_id")
private parkingUsers parkingUsers;
public parkingDetails() {}
public parkingDetails(LocalDate entryDate, LocalDateTime entryTime, LocalDate exitDate, LocalDateTime exitTime) {
this.entryDate = entryDate;
this.entryTime = entryTime;
this.exitDate = exitDate;
this.exitTime = exitTime;
}
//test
// public parkingDetails(LocalDate entryDate, LocalDateTime entryTime, LocalDate exitDate, LocalDateTime exitTime, int user_id ) {
// this.entryDate = entryDate;
// this.entryTime = entryTime;
// this.exitDate = exitDate;
// this.exitTime = exitTime;
// this.parkingUsers.setId(user_id);
// }
//setter gettrs and tostring...
In the ParkingDetails entity, you can have a setter for "parkingUsers" variable to set user object.
In your REST api's saveCarParking() method, before calling "parkingDetailsService.saveParkingUser(d);" you can pass the user object to ParkingDetails using setter created in ParkingDetails.
This should work. No need to explicitly extract the user_id from user's object to pass into ParkingDetails.
Adding one more parameter of type ‘parkingUsers‘ in the constructor of ‘ ParkingDetails’ to initialize user in parking class will also work.
(Apart, it is a good practice to start the class name with a capital letter e.g. instead of having class name as parkingDetails, it should be ParkingDetails.)

How do I add foreign keys into a new table in SpringBoot

I want to add the primary key from 2 tables (project and book mark) into a new table called ProjectBookmark which contains the primary key from my other two tables as foreign keys with the relationships shown below in springbok.
ERD Diagram
Below are my tables for Project and bookmark
Table 1
#Entity
public class Project {
#Id
#GeneratedValue
private long id;
#Column(name = "Project_Name", unique = true)
private String name;
#Column(name = "Description", unique = true)
private String description;
public Project(String name, String description) {
super();
this.name = name;
this.description = description;
}
Table 2
#Entity
public class Bookmark {
#Id
#GeneratedValue
private long id;
#Column(name = "Name", unique = true)
private String name;
#Column(name = "Type_of_resource", unique = true)
private String type;
#Column(name = "Description", unique = true)
private String description;
#Column(name = "URL", unique = true)
private String url;
public Bookmark(String name, String type, String description, String url) {
super();
this.name = name;
this.type = type;
this.description = description;
this.url = url;
}
Im not sure how to do the relationships and import in the primary keys as foreign keys to my table 3.
#Entity
public class ProjectBookmark {
}
If I understand your question correctly you need a ManyToMany relationship between Project and Bookmark.
You'll need to add the following code to your Project entity class.
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name="project_bookmark",
joinColumns = {#JoinColumn(name="project_id", referencedColumnName="id")},
inverseJoinColumns = {#JoinColumn(name="bookmark_id", referencedColumnName="id")}
)
private Set<Bookmark> bookmarks = new HashSet<>();
You don't need an additional id column in your ProjectBookmark table.

Shared Primary Key between two Entities Not Working

I have created two Entities namely Teacher and Detail, the code snippet is shown below
Teacher.java
#Entity
#Table(name = "teacher")
public class Teacher implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "age")
private int age;
#OneToOne(mappedBy = "teacher", cascade = CascadeType.ALL)
private Detail detail;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
//getter and setter
}
Detail.java
#Entity
#Table(name = "detail")
public class Detail implements Serializable {
#Id
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id")
private Teacher teacher;
#Column(name = "subjects")
private String subjects;
public Detail() {
}
public Detail(String subjects) {
this.subjects = subjects;
}
//getter and setter
}
I am trying to achieve one to one mapping with the shared primary key concept
but when i execute the controller, only Teacher table is updating with the value
try {
Teacher teacher=new Teacher("xyz",23);
Detail detail=new Detail("Java,c,c++");
teacher.setDetail(detail);
session.beginTransaction();
session.save(teacher);
session.getTransaction().commit();
model.addAttribute("added", "data inserted");
session.close();
}
After executing only Teacher table is updated with the specified values.Detail table is still showing empty
It does not work exactly like that. You still need the id field in your Detail, so add:
#Id
private long id;
to your Deatail class.
And - as comment suggests - replace the #Id annotation in field Teacher to #MapsId. This way the id of Teacher is mapped to the id of Detail BUT ONLY if you also set the teacher to the detail - you always need to set both sides of relationship - like:
teacher.setDetail(detail);
detail.setTeacher(teacher);

Spring Data JPA OneToOne Mapping returning Null

I have two Entity classes, each for my Table. They both are OneToOne-Mapped. When I read the Data, am always getting the other table's value as null.
These are my SQLs
CREATE TABLE driver_master (
unique_driver_id VARCHAR(60) PRIMARY KEY,
driver_name TEXT,
mobile_number VARCHAR (20),
vehicle_number TEXT,
vehicle_make TEXT,
seating_capacity INTEGER (10),
creation_time DATETIME
)
CREATE TABLE user_master (
user_id MEDIUMINT AUTO_INCREMENT PRIMARY KEY,
user_name TEXT,
password VARCHAR (20),
unique_driver_id VARCHAR(60),
FOREIGN KEY (unique_driver_id) REFERENCES driver_master(unique_driver_id)
)
These are my Entity classes
DriverMaster.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "driver_master")
public class DriverMaster {
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "unique_driver_id")
UUID id;
#Column(name = "driver_name")
String driverName;
#Column(name = "mobile_number")
String mobileNumber;
#Column(name = "vehicle_number")
String vehicleNumber;
#Column(name = "vehicle_make")
String vehicleMake;
#Column(name = "seating_capacity")
Integer seatingCapacity;
#Column(name = "creation_time")
OffsetDateTime creationTime;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "driverMaster")
UserMaster userMaster;
}
UserMaster.java
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "user_master")
public class UserMaster {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
Long id;
#Column(name = "user_name")
String userName;
#Column(name = "password")
String password;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "unique_driver_id", nullable = false)
DriverMaster driverMaster;
}
This is my DriverMasterRepository
public interface DriverMasterRepository extends CrudRepository<DriverMaster, Long> {
DriverMaster findById(UUID id);
}
This is my UserMasterRepository
public interface UserMasterRepository extends CrudRepository<UserMaster, Long> {
UserMaster findById(Long id);
}
I am creating DriverMaster and UserMaster at the same time. Code Snippet below
public DriverMaster create() {
UserMaster userMaster = UserMaster.builder()
.userName("xxxxx")
.password("xxxx").build();
DriverMaster driverMaster = DriverMaster.builder().driverName("TestDriver")
.creationTime(ZonedDateTime.now().toOffsetDateTime())
.seatingCapacity(8)
.mobileNumber("xxxxxxx")
.vehicleNumber("xxxx")
.vehicleMake("xxxx")
.userMaster(userMaster)
.build();
return driverUserService.create(driverMaster);
}
When i access each repository and get the data, the data for that particular table is getting populated while the referenced Object is always coming as Null.
After creation of DriverMaster, I couldn't get UserMaster within DriverMaster, it is always coming as null .
The REST Response below shows that UserMaster within DriverMaster is coming as Null
{
"id": "0d97073b-6ae2-47a9-b751-0313fd9e8ba2",
"driverName": "TestDriver",
"mobileNumber": "11111",
"vehicleNumber": "111",
"vehicleMake": "figo",
"seatingCapacity": 8,
"creationTime": "2018-02-16T15:56:50.331Z",
"userMaster": null
}
it's not a 100% problem's reason, but I believe you have to add an implementation of Serializableinterface into your entity classes.

Resources