store #ManytoOne relationship in elastiicsearch in springboot - spring-boot

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.

Related

map a #OneToMany relationship using a string column as a key

Good Morning!
I would like to know if there is a way to map a #OneToMany relationship using a string column as a key. The database in SQL Server already has all the tables, but their relationship was not made by the id, but by values ​​of type string. Can anyone help me?
Example:
student table with the fields name, phone, emailthe key of this table is the column "name"
class tablewith the fields name, date, discipline the key of this table is the column "name" that refers to "student name".
as I tried to do:
#Entity
public class Student {
...
#OneToMany(mappedBy = "student")
private List<Class> class = new ArrayList<>();
}
#Entity
public class Class{
...
#ManyToOne
#JoinColumn(name = "student_id")
private Student student;
}
When I run it through H2, it creates a column with the students' id, but I would like it to map the data that is already in the database, because I can't change the data structure. Can someone help me?
String is a valid type for an identifier. If you don't want an additional id column, you can map name as an identifier:
#Entity
public class Student {
#Id
#Column(name = "`name`")
String name;
#OneToMany(mappedBy = "student")
private List<Class> class = new ArrayList<>();
...
}
For some databases name is a special keyword, if you use #Column(name = "`name`"), Hibernate will handle it correctly.

Spring boot : LAZY Loading not working for #EmbeddedId field

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 ?

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

How to load insert scripts for multiple tables which are linked with foreign key in spring boot

I am using spring boot. I am loading test data through yml by defining spring.datasource.data=classpath:/test-data/sql_file_EntityOne.sql, classpath:/test-data/sql_file_EntityTwo.sql,...
For every single entity it works seamlessly but problem comes when EntityOne and EntityTwo have foreign key relationship and the corresponding insert statements are written in 2 different SQL files as depicted above.
I am using in memory h2 dB for local.
sql_file_EntityOne.sql
(Id_One, data_1,data_2) values(101, 'dat', 5)
sql_file_EntityTwo.sql
(Id_two, Id_Onethis is fk, data_3,data_4)
values(1,101, 'dat2', null, 5)
EntityOne
#Id
IdOne
....
#OneToMany(Cascade.All, mappedBy="entityOneRef")
List entityTwoRef
EntityTwo
#Id
IdTwo
....
#ManyToOne(Cascade.All)
#JoinColumn("entityTwoRef")
EntityOne entityOneRef
Can you please mention the error you are getting here?
You can use the following hibernate annotations for bidirectional relationship:
#OneToMany(mappedBy = ) on parent enity
#ManyToOne #JoinColumn(name = , nullable = false) on child entity
for example, let's take an example of Cart and Item as two entities with a Cart related as one to many with item:
//Cart
#Entity
#Data
public class Cart {
#Id
private Integer cartId;
#Column
private String data;
#OneToMany(mappedBy = "cart")
private Set<Item> items;
}
//Item
#Entity
#Data
public class Item {
#Id
private Integer itemId;
#Column
private String data;
#ManyToOne
#JoinColumn(name = "cart_id", nullable = false)
private Cart cart;
}
#Data is just lombok annotation for getters and setters. Scripts as below:
//Script1
INSERT INTO CART(cart_id,data) VALUES (101,'data1')
//Script2
INSERT INTO ITEM(item_id,cart_id,data) VALUES (1,101,'data2')
Then load the scripts in spring-boot in order:
spring.datasource.data=classpath:sql_script1.sql,classpath:sql_script2.sql
Hope it helps :)

spring data jpa findAll generated sql do not use join [duplicate]

I have created two entities Book and Book_Category with one-to-many relationship. When I issued BookCategoryRepository.findAll(), I expected hibernate to use 'INNER JOIN' query. But it just issued query to take data from Book_Category.
What I am missing? What should I do to make hibernate issue JOIN query?
Book.java
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#ManyToOne
#JoinColumn(name = "book_category_id")
private BookCategory bookCategory;
}
BookCategory.java
#Entity
#Table(name = "book_category")
public class BookCategory {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#OneToMany(mappedBy = "bookCategory", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Book> books;
}
BookCategoryRepository.java
public interface BookCategoryRepository extends JpaRepository<BookCategory, Integer> {
}
bookCategoryRepository.findAll()
Hibernate uses by default a second query to retriev the child collection. One reason for this is a proper limit query. Otherwise, there would be more rows in the result set, than entities for the 1 side, if at least one has more than 1 child.
There exists an annotation to change this behaviour in hibernate which is ignored by the Spring Data Jpa Repositories. The annotation is #Fetch(FetchMode.JOIN). You might consider How does the FetchMode work in Spring Data JPA if you really need this behaviour.

Resources