I have Order entity, each order has a list of Dish entity.
Only important part showed for brevity.
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Table(name = "orders")
#ToString
public class Order {
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToMany(
mappedBy = "order",
cascade = CascadeType.ALL,
orphanRemoval = true)
#ToString.Exclude
private List<Dish> dishes;
}
My front sends me a Hashmap of dish.id and quantity of this dish ordered.
To convert it to Order entity I have to add the same dish to list times it was ordered.
For example. if order has 5 dishes of id 1, I fetch id 1 and add it 5 times to list, then - save order.
To display this again in front - I use Collections.frequency to convert the Order back to Hashmap.
Should I convert my relationship container to hashmap? I've heard that I should avoid using hashmaps in Hibernate.
Related
I have a Spring boot application in which I have a one to many relationship
between my category entity and my product entity. A category contains several products
and a product belongs to one and only one category.
In the database, each category contains several registered products.
The category that contains less products in database has 1000 products
I have a category of my products in database which contains 15 000 products.
At the level of my category class, I have defined the one-to-many annotation
with the product entity and I have opted for the fetch mode = FetchType.LAZY.
This only retrieves the category entity and not the product entity.
How to do for the performance problem, because I want to create a method that
retrieves for each category, all its products and loop on it.
Even if I use the fetch mode = FetchType.EAGER,
I will have the same problem, how to better use FetchType.LAZY or FetchType.EAGER
while managing well the performance problem
#Data
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Category {
#Id
#GeneratedValue
private Integer id;
#OneToMany(mappedBy = "category")
private List<Product> product;
}
#Data
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Product {
#Id
#GeneratedValue
private Integer id;
private String code;
private double price;
#ManyToOne
#JoinColumn(name="id_cat")
private Category category;
}
How can i solve it
You have 2 options:
Eager fetch type with #Fetch(FetchMode.JOIN) (https://www.baeldung.com/hibernate-fetchmode),
JOIN FETCH (https://thorben-janssen.com/hibernate-tips-difference-join-left-join-fetch-join/)
I have property entity and floor plan entities like this
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "properties", indexes = {#Index(name = "properties_parent_id_index", columnList = "parent_id", unique = true)})
public class PropertyEntity extends BaseEntity {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "property_id")
private List<FloorPlanEntity> floorPlans;
....
...
}
now I try to delete children and save parent
like this `
propertyEntity.getFloorPlans().clear();
propertyDataService.save(propertyEntity);
but it gives exceptions like this
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "property_id" of relation "floor_plans" violates not-null constraint
I think you can use the #OneToMany(orphanRemoval = true)
It provides a way to delete orphaned entities from the database.
So, it should remove the FloorPlanEntity from database when it's removed from the list.
There is some tutorial with explanation:
https://www.baeldung.com/jpa-cascade-remove-vs-orphanremoval#orphanremoval
I have two entities, related as below
#Entity
#Table(name = "APPOINTMENT")
public class Appointment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long codeAp;
#ManyToOne(fetch = FetchType.EAGER)
, #OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn(name = "codeP")
private Patient patient;
//attributes
//getters and setters
//constructors
#Entity
#Table(name = "PATIENT")
public class Patient {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long codeP;
//attributes
//getters and setters
//constructors
I'm using JpaRepository delete method.
There is a constraint between the tables PATIENT and APPOINTMENT in database,
I want to remove orphans, when I remove Patient.
I added #OnDelete hibernate annotation but it doesn't work for me!
Can you please tell me why?
I want to keep that unidirectional relationship, can you please help me in this?
If you want to keep using the association as unidirectional only, you can define the lazy-loaded inverse side in a field without exposing getters and setters for it:
#Entity
public class Patient {
#OneToMany(mappedBy = "patient", orphanRemoval = true)
private Collection<Appointment> appointments;
}
This way orphanRemoval logic is applied from patients to their appointments and as a bonus you get the ability to navigate from patients to appointments in HQL queries.
Notice the mappedBy attribute which tells that appointments are responsible for the association management, so you continue to associate appointments with patients by setting patients in the many-to-one relation defined in the Appointment.
There is no way that you could achieve that automatic behavior on the #ManyToOne side. Its just semantically incorrect, period.
Taking under consideration though, the fact that you only want to have an uni-directional mapping and do not specify the Set<Appointment> dependency on the Patient, then a kind of workaround to your situation would be to replace the #ManyToOne with a #OneToOne relationship. Then you would be able to use orphan-removal functionality:
#OneToOne(fetch = FetchType.EAGER, orphanRemoval=true)
#JoinColumn(name = "codeP")
private Patient patient;
Keep in mind though that if you follow this path, adapt you code and at some point you will be in need to introduce #OneToMany dependency on the `Patient' side then you will stumble upon problems. So i would recommend working out pros and cons first in relation to future possible alteration to the entity graph.
I have the following entity:
#Entity
#Getter
#Setter
#ToString
public class Team extends EntityBase {
......
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY,
orphanRemoval = true, optional = false)
#JoinColumn(name = "auth_id")
private TeamAuthentication auth;
......
}
so it has a TeamAuthentication table reference. The latter entity looks as follows:
#Entity
#Getter
#Setter
#ToString
public class TeamAuthentication {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String accessToken;
}
What I want is that when I fetch existing Team entity from the table and replace a reference to TeamAuthentication table there for field auth, then persist this Team entity with teamRepository.save(), I want that old TeamAuthentication would be deleted from its table. At the moment it stays in the table and becomes sort of a loitering entry that won't be ever used or queried.
How can I leverage Hibernate cascade in deleting OneToOne reference on change?
I am trying to set a ManyToMany annotation on my code:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "user")
public class User extends AbstractUser
{
#ManyToMany(mappedBy = "promotors", cascade = CascadeType.PERSIST)
#JoinTable(name = "user_student",
joinColumns=#JoinColumn(name="promotor_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="student_id", referencedColumnName="id")
)
private Collection<User> students;
#ManyToMany
private Collection<User> promotors;
}
However every time i try to run the application and the db gets generated, it creates 2 tables for the ManyToMany, 1 new table that is called user_student as i defined beneath, but it also creates a second table user_user which i didn't define but is generated from the promotors.
It's correct you cannot map many to many relationship on one table. As you have only one possible column to map it to. What enforces one to one relationship.
You always have to have mapping table. Its also most convenient way to map many to many relationships on different tables.
Apparently, i didn't define the second ManyToMany correctly, this is the correct code:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "user")
public class User extends AbstractUser
{
#ManyToMany
#JoinTable(name = "user_student",
joinColumns={#JoinColumn(name="promotor_id", referencedColumnName="id")},
inverseJoinColumns={#JoinColumn(name="student_id", referencedColumnName="id")}
)
private Collection<User> students;
#ManyToMany(mappedBy = "students", cascade = CascadeType.PERSIST)
private Collection<User> promotors;
}