How implement ManyToOne delete on cascade? - spring-boot

This is my code
#Entity
public class School{
#Id
#GeneratedValue
private long id;
}
#Entity
public class Student{
#Id
#GeneratedValue
private long id;
#ManyToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name="STUDENT_ID")
private School school;
}
Im using JPA delete (Impl code)
#Autowired
SchoolRepository sr;
#Override
void delete(Integer id) throws Exception {
sr.deleteById(id);}
In another answer it says to set all his child to null , how i make this? Is there any way to make it easier? Thx

You must add one List of Student on Entity School annotated by #OneToMany with cascade = CascadeType.REMOVE, to remove all students of school.
#Entity
public class School{
#Id
#GeneratedValue
private long id;
#OneToMany(cascade = CascadeType.REMOVE, mappedBy = "school")
private List<Student> students;
}
#Entity
public class Student{
#Id
#GeneratedValue
private long id;
#ManyToOne
#JoinColumn(name="STUDENT_ID")
private School school;
}

Related

Composite Primary Key and #OneToOne JPA - Hibernate

My entities are as follows
Office
#Entity
public class Office {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int latitude;
private int longitude;
private String buildingName;
// getters and setters omitted for brevity
}
Point - which is an EmbeddedId
#Embeddable
public class Point implements Serializable {
private int latitude;
private int longitude;
// getters and setters omitted for brevity
}
Location
#Entity
public class Location {
#EmbeddedId
private Point point;
private String country;
#OneToOne // How to add a OneToOne Mapping
private Office office;
// getters and setters omitted for brevity
}
Question:
I want to add a one-to-one mapping between the Office and the Location entity.
What I've tried:
I added the following annotations along with #OneToOne mapping in the Location entity
#JoinColumn(name = "latitude", referencedColumnName = "latitude")
#JoinColumn(name = "longitude", referencedColumnName = "longitude")
but I got the following error
Provided id of the wrong type for class com.example.demo.entity.employee.o2m_cpk.Office. Expected: class java.lang.Integer, got class com.example.demo.entity.employee.o2m_cpk.Point
Use the following mappings:
#Entity
public class Office {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#OneToOne(mappedBy = "office")
private Location location;
private String buildingName;
}
#Embeddable
public class Point implements Serializable {
private int latitude;
private int longitude;
}
#Entity
public class Location {
#EmbeddedId
private Point point;
private String country;
#OneToOne
private Office office;
}

Why I can't delete data in cascade way?

The problem is when I want to delete user I'm getting error in Spring Boot like that:
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (32506632_pam.badge, CONSTRAINT FK4aamfo6o0h5ejqjn40fv40jdw FOREIGN KEY (user_id) REFERENCES user (id))
I'm guessing that I need to delete data in cascade way. So I've placed CascadeType.REMOVE value to #OneToOne annotation like that, but it doesn't work:
badge entity
#Entity
#Data
#Table(name = "badge")
#AllArgsConstructor
#NoArgsConstructor
public class Badge {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonManagedReference
#ManyToMany(mappedBy = "badges", fetch = FetchType.LAZY)
private List<Reader> readers;
#OneToOne(cascade = CascadeType.REMOVE, orphanRemoval=true)
#JoinColumn(name = "user_id")
private User user;
private String number;
#Lob
#Basic(fetch = FetchType.LAZY)
private byte[] photo;
}
user entity
#Entity
#Data
#Table(name = "user")
#AllArgsConstructor
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String lastname;
private String pesel;
private String email;
private String telephone;
private Integer age;
private String gender;
}
reader entity
#Entity
#Data
#Table(name = "reader")
#AllArgsConstructor
#NoArgsConstructor
public class Reader {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonBackReference
#ManyToMany(fetch = FetchType.LAZY)
private List<Badge> badges;
private String department;
private String room;
private Boolean status;
}
Class which loads initial data
#Component
public class DataLoader implements ApplicationRunner {
#Autowired
private UserService userService;
#Autowired
private BadgeService badgeService;
#Autowired
private ReaderService readerService;
#Override
public void run(ApplicationArguments args) throws Exception {
User user1 = new User(null, "Jan", "Kowal", "11111111111", "jan#kowal.pl", "+48111111111", new Integer(23), "male");
userService.saveUser(user1);
Reader reader1 = new Reader(null, null, "Warehouse", "207A", new Boolean("true"));
Badge badge1 = new Badge(null, Arrays.asList(reader1), user1, "738604289120", null);
badgeService.saveBadge(badge1);
reader1.setBadges(Arrays.asList(badge1));
readerService.saveReader(reader1);
}
}
Endpoint for deleting user - it uses repository which extends CrudRepository and uses default delete behavior.
#DeleteMapping("/deleteUserById/{id}")
private void deleteUserById(#PathVariable Long id) {
userService.deleteUserById(id);
}
Database structure in phpmyadmin
My goal is to delete user and associated badge with him, then to delete row in reader_badges table.

How to create JPA Specification for multiple tables?

I had entities User, BlockUnit, Block and Unit as Follows.
User has ManyToMany relation with blockunit.
#Entity
public class User {
#ManyToMany
private Set<BlockUnit> blockUnits;
}
#Entity
public class BlockUnit {
#Id
private Long id;
#OneToOne(targetEntity = Block.class)
#JoinColumn(name = "block_id")
private Block block;
#OneToOne(targetEntity = Unit.class)
#JoinColumn(name = "unit_id")
private Unit unit;
#ManyToMany(fetch = FetchType.LAZY)
private Set<User> users = new HashSet<>();
}
BlockUnit has OneToOne relation with Block and Unit.
#Entity
public class Block {
#Id
private Long id;
}
#Entity
public class Unit {
#Id
private Long id;
}
How should I create the JPA criteria specification for above in order to select user's having Block ID and Unit ID?
Thank you very much in advance!

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 Boot : Error :Cannot call sendError() after the response has been committed

I am getting this error .
Cannot call sendError() after the response has been committed
Can someone help me figure out why?.
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToOne(
fetch = FetchType.LAZY,
cascade = CascadeType.ALL
)
#JoinColumn(name = "details_id")
private Details details;
//Getters and setters left out for brevity
}
#Entity
public class Details {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String description;
private float price;
private float discount;
#OneToOne(mappedBy = "details")
private Product product;
}
#RestController
public class ProductController {
#Autowired
ProductRepository productRepository;
#GetMapping("/getAllProducts")
public Iterable<Product> getAllProducts(){
return productRepository.findAll();
}
}
#RestController
public class DetialsController {
#Autowired
ProductRepository productRepository;
#Autowired
DetailsRepository detailsRepository;
#PostMapping("/details")
public Details addDetails(#RequestBody Details details) {
Product newProduct = new Product();
newProduct.setDetails(details);
productRepository.save(newProduct);
return detailsRepository.save(details);
}
}
I am able to make the POST call to /details; for adding details successfully. But when i make GET call to /getAllProducts, I am getting this error
Cannot call sendError() after the response has been committed
This is an issue with bidirectional relationships, as they hold references to each other, at deserialization, Jackson runs in an infinite loop. My first suggestion would be adding #JsonIgnore to one end of the relation.
#OneToOne(mappedBy = "details")
#JsonIgnore
private Product product;
Afterward, if that solved your issue, you can look over #JsonManagedReference/#JsonBackReference and #JsonIdentityInfo.
You can also look over this link for more insight
You can use this :
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JsonBackReference(value = "details_id")
#OneToOne(
fetch = FetchType.LAZY,
cascade = CascadeType.ALL
)
#JoinColumn(name = "details_id")
private Details details;
//Getters and setters left out for brevity
}
#Entity
public class Details {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String description;
private float price;
private float discount;
#JsonManagedReference(value = "details")
#OneToOne(mappedBy = "details",,cascade=CascadeType.ALL)
private Product product;
}

Resources