Spring boot : LAZY Loading not working for #EmbeddedId field - spring-boot

I have EmbeddedId which has field which need to be loaded lazy. In service class on fetching TeacherStudent it also fetch student EAGERLY which should be LAZY fetch. what changes are needed to make student being fetched as lazy ?
TeacherStudent.class ---> making student load as lazy
class TeacherStudent
{
public static final String TEACHER = "TeacherStudentPk.teacher";
public static final String STUDENT = "TeacherStudentPk.student";
#EmbeddedId
TeacherStudentPk teacherStudentPk = new TeacherStudentPk();
#ToString.Exclude
#Transient
Teacher teacher;
#ToString.Exclude
#Transient
Student student;
}
Getting Teacher Student data from teacher table
TeacherStudentpk.class
#Embeddable
class TeacherStudentPk{
#ManyToOne(fetch = FetchType.LAZY , optional = false)
#JoinColumn(name = "student_pk")
Student student; **<------------- student marked as lazy**
Teacher teacher;
}
TecherService.class
class TeacherService{
void getTeacherStudent(Teacher teacher){
Set<TeacherStudent> teacherStudent =
teacher.getTeacherStudent(); **<-----eager
fetching student which is of lazy type**
}
}
How should I change in TeacherStudent table to make student as fetch lazy ?

Related

store #ManytoOne relationship in elastiicsearch in springboot

I am using JpaRepository and ElasticsearchRepository(spring-data-3.x) in spring boot Application ,saving data in relational db as well as in elasticsearch.
Below is Student Entity
#Entity
#Table(name = "student")
#Document(indexName = "student" ,type="_doc")
class Student{
#id
private Long id;
private String studentName;
----
}
Below is course entity
#Entity
#Table(name = "course")
#Document(indexName = "course" ,type="_doc")
class Course{
#Id
private Long id;
private String courseName;
------
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "courses", allowSetters = true)
private Student student;
}
When I saved data in db using repository ,id of student is stored in course relation and when we fetch data ,course data fetched with student. But when I store data in elasticsearch student data stored as a sub-document in course document. If I make any updation in student like change student name and then search course for that student from elastic search .It shows old data as on updation sub-document is not updated. So How we can store data in elasticsearch when we are using relationship #ManyToOne.

fetch list based on id present in another entity

this is my order entity,
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "ordertab")
public class Order {
#Id
private int orderId;
private String orderDate;
#ManyToMany(targetEntity = Medicine.class,cascade = CascadeType.ALL)
#JoinTable(name="ord_med",
joinColumns = {#JoinColumn(name="ord_id")},
inverseJoinColumns = {#JoinColumn(name="med_id")})
private List<Medicine> medicineList;
private String dispatchDate;
private float totalCost;
#ManyToOne(targetEntity = Customer.class,cascade = CascadeType.ALL)
#JoinColumn(name= "custord_fk",referencedColumnName = "customerId")
private Customer customer;
private String status;
}
and this is my medicine entity,
#Data
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
public class Medicine {
#Id
private String medicineId;
private String medicineName;
private float medicineCost;
private LocalDate mfd;
private LocalDate expiryDate;
**#ManyToMany(cascade = CascadeType.ALL, mappedBy = "medicineList")
private List<Order> orderList;** //order/ medicine many to many mapping
// OneToOne Mapping
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "categoryId", referencedColumnName = "categoryId")
private Category category;
in my order service interface i have a method,
List showAllOrder(string medId);
I have to fetch all orders that has the matching med id.
this many to many mapping have created a additional table ord_med with two columns named ord_id,med_id(type foreign keys).In addition to that due to this bidirectional mapping(i believe it is) while creating object of medicine entity its asking me to add orderlist ,how to approach this method or how exactly should i solve this. thankyou.
in your OrderRepository you can implements this method
findByMedicineId(String id);
if i go for findByMedicineId(String id);
it gives error saying no property medicineId is found in Order entity,cuz the property medicineId is in Medicine entity,while defining custom method in repository follows rules, refer https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
anyway I have found the solution for this,
public List<Order> getOrderListBasedOnMedicineId(String medicineid) {
Optional<Medicine> med=medicineRepo.findById(medicineid);//find if medicine is present in database with the id.
if(med.isEmpty()) {
return null;
}
List<Order> orders = medicineServ.getOrderList(); //getorderlist defined in service implementation of medicine.
List<Order> ordersWithMedId = new ArrayList();//new list to add all orders that has atleast one medicineId that matches.
for(int i=0;i<orders.size();i++) {
List<Medicine> medicines= orders.get(i).getMedicineList();
for(int j=0;j<medicines.size();j++) {
ordersWithMedId.add(orders.get(i));
}
}
return ordersWithMedId;//returning the list of orders.
}
#Override
public List<Order> getOrderList() {//medicine service implementation
return orderRepo.findAll();
}
//OrderController
#GetMapping("/orders/list/{id}")
public ResponseEntity<List<Order>> getOrderListBasedOnMedicineId(#PathVariable("id") String id) {
List<Order> ord= orderService.getOrderListBasedOnMedicineId(id);
if(ord==null) {
throw new OrderNotFoundException("Order not found with medicine id:"+id);
}
return new ResponseEntity<List<Order>>(orderService.getOrderListBasedOnMedicineId(id),HttpStatus.OK);
}

Can Spring Data JPA Enforce ManyToOne Relationship via #JoinColumn

I have a Spring Boot application using Spring Data REST and Spring Data JPA. I have two domain entities: Student and Classroom, where many students can belong to the same classroom.
Student:
#Data
#Entity
#Table(name = "STUDENT")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "STUDENT_ID")
private Integer studentId; // This Id has been setup as auto generated in DB
#Column(name = "ROOM_ID")
private Integer roomId;
#ManyToOne
#JoinColumn(name = "ROOM_ID", nullable = false, updatable = false, insertable = false)
private Classroom classroom;
}
Classroom:
#Data
#Entity
#Table(name = "CLASSROOM")
public class Classroom {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ROOM_ID")
private Integer roomId; // This Id has been setup as auto generated in DB
#OneToMany(mappedBy = "classroom")
private List<Student> studentList;
.....// other fields related to a classroom
}
And the Student repository:
public interface StudentRepository extends CrudRepository<Student , Integer>{
List<Student> findByClassroom(#Param("room") Classroom room);
}
And the Classroom repository:
public interface ClassroomRepository extends CrudRepository<Classroom , Integer>{
}
And I have a SpringApplication main file, but no controller.
There is already one classroom with room id=1 in the CLASSROOM table. When I gave the following request to POST to http://localhost:8080/students, a new student record was created in the Student table, which I expected it to fail because there isn't a classroom with id=100 exists in the CLASSROOM.
So my question is that: can Spring Data JPA enforce a manyToOne relationship or this foreign key enforcement has to be done on the database side (the not-null ROOM_ID column in the Student table is NOT defined as foreign key by our DBA for a legitimate consideration). If it has to be done on the database side, what is the point to define the manyToOne relationship in entity files?
Also, I know that I have redundant classroom fields in the Student entity, I just don't know which one to keep in the Student entity (the roomId or the "classroom" field), because when I create a student, I want to give only the roomId of a classroom in the request. Thanks!
{
"roomId": 100 // I expect this request to fail because no roomId=100 in the CLASSROOM table.
}
what is the point to define the manyToOne relationship in entity files
Because is an Object Relational Mapping tool that allows you define entity graphs.
You are currently passing roomId which in your Entity is just another field so you needs to remove that.
#Entity
#Table(name = "STUDENT")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "STUDENT_ID")
private Integer studentId; // This Id has been setup as auto generated in DB
#ManyToOne
#JoinColumn(name = "ROOM_ID", nullable = false)
private Classroom classroom;
}
In Spring Data Rest you then defined an association by passing the self link of the referenced entity.
Your request then needs to look like the below:
{
"classroom" : "http://localhost:8080/classrooms/1"
}
Also removing the ID as you are POSTing a new record and, as you note, the ID is auto-generated in the database.
See also:
https://www.baeldung.com/spring-data-rest-relationships

Why hibernate entity graph fetch nested lazy collections

I am trying to use entity graph for triggering lazy collections to load but unfortunately entity graph also triggers all nested collections. I am using spring-data-jpa-entity-graph library for creating entity graphs at runtime.
#Entity
public class Brand implements Serializable {
#OneToMany(mappedBy = "brand", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<Vehicle> vehicles;
}
#Entity
public class Vehicle implements Serializable {
#ManyToOne
#JoinColumn(name = "brand_id")
private Brand brand;
#OneToMany(mappedBy = "vehicle", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<VehiclePart> parts;
}
#Entity
public class VehiclePart implements Serializable {
#ManyToOne
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
}
Spring service with JPA repository:
public interface BrandsRepository extends EntityGraphJpaRepository<Brand, Long> {
Page<Brand> findAll(Pagable pagable, EntityGraph entityGraph);
}
#Service
public class BrandsService {
public List<Brand> find() {
return repository.findAll(PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "id")), EntityGraphUtils.fromAttributePaths("vehicles")).getContent();
}
}
In this case service also return parts collection for each vehicle but I would like to fetch only list of brands with vehicles collection for each brand.
How can we trigger to load lazy collections just on the first level (only brand's vehicles -- without vehicle's parts)?
I had the same problem. In my case: Spring and hibernate acted correctly, but I can see, that unused (lazy) fields are queried from sql.
When you use the fields, then they will be loaded over sql.
Iam using lombok and #EqualsAndHashCode.Exclude and #ToString.Exclude helps to prevent that.
In your case: Add a DTO-layer. Do not return the entities themself.
Or use #JsonIgnore annotation to ignore fields.

Zero to One (Optional One to One) Entity Relationship Issue (attempted to assign null one-to-one property)

Unable to update entity for optional one to one relationship using spring data jpa(2.1.2.RELEASE) and spring boot(2.1.2.RELEASE)
Getting the error attempted to assign null one-to-one property
#Entity
#Table(name = "table_a")
public class EntityA {
#Id
String id;
String aa;
int bbb;
#Nullable
#OneToOne(mappedBy = "inv", optional = true,cascade = CascadeType.ALL)
EntityB bEntity;
}
#Entity
public class EntityB{
#Id
String id;
String aaa;
String nnnn;
#OneToOne
#MapsId
#JoinColumn(name = "id")
EntityA aEntity;
}
DAO Code as below
Optional eA = entARepo.findById("1234");
EntityA entA= null;
if (eA.isPresent()) {
entA= eA.get();
}
EntityB eB = entA.getBEntity();
if (Objects.isNull(eB)) {
eB= new EntityB();
eB.setAAA("12121");
eB.setAEntity(entA);
entA.setBEntity(entB);
}
repository.save(entA);
}``
I resolved this by using a join table instead of a shared primary key approach. would still to know how to make the shared primary key approach work for optional one to one relationship

Resources