Record not inserted while using #ManyToOne mapping - spring

I have 2 tables 'orders' and 'orderlines' and used bidirectional OneToMany mapping.When i save the order, record is successfully inserted into table 'orders'.But my 'orderlines' table is empty.No record is inserted.
This is the save operation code in Controller.
#RequestMapping(value = "ordersuccess", method = RequestMethod.POST)
public String processOrder(#ModelAttribute("order") Order order,
#ModelAttribute("cart") Cart cart,
BindingResult result) {
if (!result.hasErrors()) {
Set<OrderLine> orderLines = new HashSet<OrderLine>();
for(CartLine c : cart.getCartLines()) {
OrderLine line = new OrderLine();
line.setOrder(order);
line.setProduct(c.getProduct());
line.setProductPrice(c.getProduct().getPrice());
line.setTotalPrice(c.getPrice());
orderLines.add(line);
order.setOrderLines(orderLines);
}
orderService.save(order);
orderLineService.save(orderLine);
}
return "ordersuccess";
}
Can someone point me what wrong i am doing.
EDIT:
OrderLine.java
public class OrderLine {
#Id
#GeneratedValue
#Column(name="orderline_id")
private int orderline_id;
#ManyToOne
#JoinColumn(name = "order_id")
private Order order;
#ManyToOne(targetEntity = Product.class,
cascade = CascadeType.ALL,
fetch = FetchType.LAZY)
#JoinTable(
name="products",
joinColumns=#JoinColumn(name="product_id")
)
private Product product;
)
Order.java
public class Order {
#Id
#GeneratedValue
#Column(name="id")
private int id;
#OneToMany(mappedBy = "order")
private Set<OrderLine> orderLines;
//getter/setter

The orderLines object is created:
Set<OrderLine> orderLines = new HashSet<OrderLine>();
You then add lines to it:
orderLines.add(line);
But it never attributed to an order or sent to the service layer.
Also the OrderLine.product mapping should be like this
public class OrderLine {
#Id
#GeneratedValue
#Column(name="orderline_id")
private int orderline_id;
#ManyToOne
#JoinColumn(name = "order_id")
private Order order;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "product_id")
private Product product;
}
and Order.orderLines should have a cascade:
public class Order {
#Id
#GeneratedValue
#Column(name="id")
private int id;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private Set<OrderLine> orderLines;
}
You then need to save the orderLines:
order.setOrderLines(orderLines);
and save the order:
orderService.save(order);
When order is saved it will cascade the orderlines and the associated product too.
If you have bidirectional associations don't forget to set both sides.

Related

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException

This is my orderservice implementation for creating and saving orders here with the customerid I'm getting customer and customer has a cart and in the cart product list is there and for that product list, I should create an order.
public Order save(int custid) {
Optional<Customer> cust = customerRepo.findById(custid);//here customer is there and inside customer cart is there inside cart medicine list is there.
Cart ct= cust.get().getCart();//getting cart from customer
if(ct.getMedicineList().size()!=0) {//create order only if the medicine list is not empty. there are 8 fields **orderDate,dispatchDate,status,medicineList,totalCost,customer and orderId(GeneratedValue)** I can't set the orderId cuz it is auto generated.
LocalDate todaysDate = LocalDate.now();
LocalDate dispatchdate = todaysDate.plusDays(3);
List<Medicine> orderList= new ArrayList<Medicine>();
List<Medicine> cartList= new ArrayList<Medicine>();
cartList=ct.getMedicineList();
orderList.addAll(cartList);
Order ord = new Order();
ord.setCustomer(cust.get());
ord.setMedicineList(orderList);
ord.setDispatchDate(dispatchdate);
ord.setOrderDate(todaysDate);
ord.setStatus("Placed");
ord.setTotalCost((float)ct.getTotalAmount());
logger.info("Add order to the database");
return orderRepository.save(ord);
}
return null;
}
this is my order controller
#PostMapping("/order/{custid}")
public ResponseEntity<Order> addOrder(#Valid #PathVariable("custid") int custid) {
logger.info("Add order in database");
return new ResponseEntity<>(orderService.save(custid), HttpStatus.OK);
}
this is my medicine Entity
#Data
#RequiredArgsConstructor
#ToString
#Table(name = "medicine")
#Entity
public class Medicine {
#Id
#Column(name = "medicine_id", nullable = false)
#NonNull
#GeneratedValue
private int medicineId;
#NonNull
#Size(min = 3, message = "Minimum charecters in medicine name should be 3.")
#NotEmpty
#Column(unique = true, name = "medicine_name", nullable = false)
private String medicineName;
#NonNull
#Column(name = "medicine_cost", nullable = false)
private float medicineCost;
#NonNull
#Column(name = "mfd", nullable = false)
private LocalDate mfd;
#NonNull
#Column(name = "expiry_date", nullable = false)
private LocalDate expiryDate;
#NonNull
#Column(name = "medicine_quantity", nullable = false)
private int medicineQuantity = 1;
#NonNull
private String medicineCategory;
#NonNull
private String medicineDescription;
#JsonIgnore
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "medicineList",fetch = FetchType.EAGER)
private List<Order> orderList;
}
this is my order Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Order {
#Id
#Column(name = "orderId")
#GeneratedValue
private int orderId;
#NonNull
private LocalDate orderDate;
#ManyToMany(targetEntity = Medicine.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "ord_med", joinColumns = { #JoinColumn(name = "ord_id") }, inverseJoinColumns = {
#JoinColumn(name = "med_id") })
private List<Medicine> medicineList = new ArrayList<>();
#NonNull
private LocalDate dispatchDate;
#NotEmpty
private float totalCost;
#NonNull
private String status;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="c_ord_fk",referencedColumnName = "customerId")
#NonNull
private Customer customer;
}
here when i try to create order for the list inside cart it gives me [36m.m.m.a.ExceptionHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction]
i'm not sure but i think its because of the id but it is autogenerated. Idk how to create an order object for the list of products or is this the correct way to do it.
Actually I found the answer, all I have to do is when you use ManyToMany mapping the cascade type must be cascade = {CascadeType.MERGE,CascadeType.REFRESH} instead of {cascade = CascadeType.ALL} and it works fine. reference JPA: detached entity passed to persist: nested exception is org.hibernate.PersistentObjectException

jpa - list OneToMany not saved

I have the below room entity which has many disponibilities, when i add a room with a list of disponibilities, the room is saved but the list is not. what am i missing in the relationship ?
#Entity
public class RoomEntity {
#Id
private String classRoomId;
private String label;
#OneToMany(mappedBy = "room", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<DisponibilityEntity> disponibilities;
public void addDisponibilities(List<DisponibilityEntity> disponibilityEntities) {
if (CollectionUtils.isEmpty(disponibilities)) {
disponibilities = new ArrayList<>();
}
disponibilities.addAll(disponibilityEntities);
disponibilityEntities.forEach(item -> item.setRoom(this));
}
}
#Entity
public class DisponibilityEntity {
#Id
private String disponibilityId;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_room")
private RoomEntity room;
}
roomEntity.addDisponibilities(classRoomEntity.getDisponibilities());
roomRepository.save(roomEntity);

#One-to-Many relationship does not working in Spring

I have an Entity Recipe with a relationship OneToMany with Ingredients.
#Entity
public class Recipe {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
#OneToOne(cascade = CascadeType.ALL) // se eliminiamo la Recipe eliminiamo anche notes
private Notes notes;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe")
private Set<Ingredient> ingredients;
#ManyToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "recipe_category",
joinColumns = #JoinColumn(name = "recipe_id"),
inverseJoinColumns = #JoinColumn(name = "category_id"))
private Set<Category> categories;
...getter and setter...
}
And an Entity Ingredient:
#Entity
public class Ingredient {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
private int amount;
#ManyToOne
private Recipe recipe;
...getter and setter...
}
In order to test it I have used a controller to insert and retrieving all row:
#GetMapping({"","/"})
public List<Recipe> allRecipe() {
return recipeRepository.findAll();
}
#GetMapping("/insert")
public Recipe addRecipe() {
Set<Ingredient> ingredients = new HashSet<>();
ingredients.add(new Ingredient("ingredient-"+Math.random(), 10));
Recipe newRecipe = new Recipe("Recipe-"+Math.random(),
null, ingredients, null);
return recipeRepository.save(newRecipe);
}
The repository is a JPA Repository.
I do not have any errors, but when I try to retrieve an object I get no ingredients even though they are saved on the table (but with recipe_id = null).
How can I solve this problem?
Initialize your ingredients as
#OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe")
private Set<Ingredient> ingredients = new HashSet<>();
Change your your controller to,
#GetMapping("/insert")
public Recipe addRecipe() {
Ingredient ingredient = new Ingredient("ingredient-"+Math.random(), 10));
Recipe newRecipe = new Recipe("Recipe-"+Math.random(),
null, null); //constructor without ingredient arg
newRecipe.getIngredients.add(ingredient);
ingredient.setRecipe(newRecipe);
return recipeRepository.save(newRecipe);
}

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);

Register data into Many-to-Many Relation Table

I have 'Course' and 'Student' entities. They have many-to-many relation. So, i have COURSE_STUDENT(contains 'student_id' and 'course_id' columns) table. I want to register students to courses with a button.(For example; a student lists courses and click Register button to register a specific course).
When i want to create new courses, i use courseRepository and courseMapper which comes from JHipster by default.
But i don't have repository and mapper files for COURSE_STUDENT. Because it is not actually a main entity. It is created for many-to-many relation.
How can i register students to courses?
Git repo:https://github.com/canberkizgi/monolithic-mucs
My course entity:
#Entity
#Table(name = "course")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name = "title", nullable = false)
private String title;
#Column(name = "description")
private String description;
#ManyToOne
private Instructor instructor;
#ManyToMany(fetch = FetchType.EAGER)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "course_student",
joinColumns = #JoinColumn(name="courses_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="students_id", referencedColumnName="id"))
private Set<Student> students = new HashSet<>();
Student entity:
#Entity
#Table(name = "student")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
#JoinColumn(unique = true)
private User user;
#ManyToMany(fetch = FetchType.EAGER,mappedBy = "students")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Course> courses = new HashSet<>();
For example; Createcourse function with Mapper and Repository
#PostMapping("/courses")
#Timed
public ResponseEntity<CourseDTO> createCourse(#Valid #RequestBody CourseDTO courseDTO) throws URISyntaxException {
log.debug("REST request to save Course : {}", courseDTO);
if (courseDTO.getId() != null) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new course cannot already have an ID")).body(null);
}
Course course = courseMapper.toEntity(courseDTO);
course = courseRepository.save(course);
CourseDTO result = courseMapper.toDto(course);
return ResponseEntity.created(new URI("/api/courses/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
.body(result);
}
The relationship is owned by the course entity. Thats because on the student side the #ManyToMany annotation has a mappedBy attribute. This means, that the database will reflect the set in the course. You need to add students to that set to save the relationship. That change needs to be done within a transaction.
That being said it would probably be best to follow DDD here. I would create a registerTo method in the student class that would take the course as a parameter. I would then call this.courses.add(course) and course.getStudents().add(this) in that method.

Resources