Print sub categories list with categories in JSON response - spring

I have mysql table like this
https://i.stack.imgur.com/ON3JL.png
this is entity class for this table
Where(clause = "active =1")
#Entity
#Table(name = "category", catalog = "businessin")
public class Category implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
private String name;
private Integer parentId;
private Integer active;
private String pic;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
private List<Product> products = new ArrayList<Product>();
setters&getter
}
I'm building RESTful API using spring rest and spring data (jpaRepositories)
I want when printing main categories from controllers as JSON reponse i want them to have also a list of subCategories
example for this
[
{
id: 1,
name: "Electronics",
parentId: 0,
active: 1,
pic: null
}]
to this
[
{
id: 1,
name: "Electronics",
parentId: 0,
active: 1,
pic: null
subCategories: [Mobile, Laptops]
}]

it's simple make your entity like this
#Where(clause = "active =1")
#Entity
#Table(name = "category" )
public class Category implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
private String name;
#Column(nullable=false,columnDefinition="int default 1")
private Integer active;
private String pic;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
private List<Product> products = new ArrayList<Product>();
#ManyToOne
#JoinColumn(name="parent_id")
#JsonIgnore
// #ColumnDefault("0")
private Category parentId;
#OneToMany(mappedBy="parentId")
private List<Category> subCategories=new ArrayList<>();
setters and getters
}

Related

JPA, Simple One-To-Many Relationship Fetching Problem

Simple Fetch Problem I'm facing in a straight-forward OneToMany Relationship: One Author Many Books.
Here's Author :
#Entity
#Table(name = "authors")
public class AuthorEntity {
#Id
#GeneratedValue
private UUID id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#OneToMany(
mappedBy = "author",
orphanRemoval = true,
fetch = FetchType.EAGER
)
private List<BookEntity> books; // Getters and Setters
}
Here's Book:
#Entity
#Table(name = "books")
public class BookEntity {
#Id
#Column(name = "id")
#GeneratedValue
private UUID id;
#Column(name = "title")
private String title;
#ManyToOne(optional = false)
#JoinColumn(
name = "author_id",
referencedColumnName = "id"
)
private AuthorEntity author;
// Getters and Setters
}
I saved an author and a book through their respective repositories and I checked everything is fine, and here's my query to fetch the author :
SELECT a FROM AuthorEntity a JOIN a.books WHERE a.id = :authorId
Now when I try to access author.getBooks() it says it is null, why doesn't it fetch ? Why do I always have to fetch the books separately ? What's the right query ?

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 - How to update child object in OneToMany relationship?

I have a Customer class where each customer can have multiple Products. The class is as follow:
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#OneToMany(targetEntity=Product.class, mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#JsonManagedReference
private List<Product> products = new ArrayList<>();
//getters and setters here
}
and the Product class holds OneToOne relation with other Classes and it is as follows:
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(targetEntity=Customer.class, fetch = FetchType.LAZY)
#JoinColumn(name = "customer_id")
#JsonBackReference
private Customer customer;
#OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#JsonManagedReference
private SomeType1 someType1;
#OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#JsonManagedReference
private SomeType2 someType2;
#OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#JsonManagedReference
private SomeType3 someType3;
#OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#JsonManagedReference
private SomeType4 someType4;
//getters and setters here
}
I am trying to achieve following functionality with this:
Given Customer ID and Product ID, update the values in SomeType1, SomeType2, SomeType3 classes. I am getting the updated SomeType1, SomeType2, SomeType3 objects from UI and I want to update the values in DB. I already have PUT method in place for this.
Here's the PUT method:
#PutMapping(value = "customer/{id}/product/{product_id}")
#ResponseBody
public ResponseEntity<Product> updateProduct(#PathVariable final String id,
#PathVariable final String product_id, #RequestBody final Product product) {
Optional<Customer> customerInDb = customerService.getCustomerById(id);
if (!customerInDb.isPresent()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
MessageFormat.format("Customer with id {0} does not exist.", id));
} else {
product.setId(Long.valueOf(product_id));
product.setCustomer(customerInDb.get());
Product savedProduct = customerService.createProduct(product);
return ResponseEntity.ok(savedProduct);
}
}
I am getting following error for this REST call:
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.myapp.arg.entities.SomeType2#12]
What could be the reason for this?
createProduct method:
#Override
public Product createProduct(Product product) {
Product savedProduct = productRepository.save(product);
return savedProduct;
}
JSON input to the PUT method:
{
"id":9,
"someType1":{
"id":9,
"avg":20,
"total":20
},
"someType2":{
"id":9,
"circum":45.0,
"strength":45.0,
"totalNav":0.0
},
"someType3":{
"id":9,
"tensile":87,
"pull":128,
"push":56,
"upward":28.0
},
"measuredBy":"SJ",
"addedDate":"2021-05-23",
"type":"Prime"
}
you are using the same id for all of your entities. ID must be unique

Spring data JPA populate data of 2 One-To-Many relationship

I have a ManyToMany relationship that is broken down into 2 OneToMany relation. A Book can belong to multiple Categories and a Category can have many Books.
When I query for Book, the categories list just get empty. How can I get a list of all Categories that a Book belong to ? Am I missing something ?
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotBlank(message = "Please input book title")
private String title;
private Integer publishYear;
private String publisher;
private String language;
private Integer numberOfPages;
private String avatarUrl;
#OneToMany(targetEntity = BookCategory.class, cascade = CascadeType.ALL)
#JoinColumn(name = "category", nullable = false, insertable = false, updatable = false)
private Set<BookCategory> categories = new LinkedHashSet<>();
}
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(nullable = false)
#NotBlank(message = "Please input category name")
private String name;
}
#Entity
public class BookCategory {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToOne
#JoinColumn(name = "book", nullable = false)
private Book book;
#ManyToOne
#JoinColumn(name = "category", nullable = false)
private Category category;
}
Try using mappedBy attribute with #OneTOMany annotation on the 'One' side of the OneToMany relation.
Or you can also try using the following:
#ManyToMany
#JoinTable(
name = “book”_category,
joinColumns = #JoinColumn(name = “book_id”),
inverseJoinColumns = #JoinColumn(name = “category_id))
Read more:
https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/

JPA - Issue with OneToOne relationship when two foreign keys are primary key to entity

Two foreign keys act as primary key in entity for OneToOne, I'm getting error "Provided id of the wrong type for class ....."
When I tried to POST data, It's getting inserted correctly but GET is not working.
If I change OneToOne to OneToMany it is working for POST & GET both.
Request:
{
"items": [
{
"applicant": {
"guests": [
{
"seqNumber": 1,
"name": "name",
"gender": "gender"
}
]
}
}
]
}
Back Reference:
reservation.getItems().forEach(i -> {
i.setReservation(reservation);
i.getApplicant().setItem(i);
i.getApplicant().getGuests().forEach(g -> g.setApplicant(i.getApplicant()));
});
Reservation Entity:
#Entity
#Getter
#Setter
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_RESERVATION", nullable = false, updatable = false)
private String reservationId;
#OneToMany(mappedBy = "reservation", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
private Set<Item> items = new HashSet<>();
}
Item Entity:
#Entity
#Getter
#Setter
#IdClass(Item.ItemKey.class)
public class Item {
#Id
#Column(name = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
private long itemReservationId;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false)
#JsonBackReference
private Reservation reservation;
#OneToOne(mappedBy = "item", cascade = CascadeType.ALL)
#JsonManagedReference
private Applicant applicant;
#Data
static class ItemKey implements Serializable {
private Reservation reservation;
private long itemReservationId;
}
}
Applicant Entity:
#Entity
#Getter
#Setter
#IdClass(Applicant.ApplicantKey.class)
public class Applicant {
#Id
#OneToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false),
#JoinColumn(name = "ID_ITEM_RESERVATION", referencedColumnName = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
})
#JsonBackReference
private Item item;
#OneToMany(mappedBy = "applicant", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
private Set<Guest> guests = new HashSet<>();
#Data
static class ApplicantKey implements Serializable {
private Item item;
}
}
Guest Entity:
#Entity
#Getter
#Setter
#IdClass(Guest.GuestKey.class)
public class Guest {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false),
#JoinColumn(name = "ID_ITEM_RESERVATION", referencedColumnName = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
})
#JsonBackReference
private Applicant applicant;
#Id
#Column(name = "S_NUMBER", nullable = false, updatable = false)
private Short seqNumber;
#Column(name = "N_NAME")
private String name;
#Column(name = "CD_GENDER")
private String gender;
#Data
static class GuestKey implements Serializable {
private Applicant applicant;
private Short seqNumber;
}
}
Expected output must be same as Request but getting error " ... Provided id of the wrong type for class ..."
Here is the code.

Resources