Entity A has OneToOne relation with Entity B, when a data is inserted in A, entity B also gets inserted the same id as A - spring

So, I have a Student entity and a ShoppingCart entity.
What I wanted to achieve is, when I insert data for student, let's say studentId = 1, the cartId automatically has 1 inserted. For example:
Student table
student_id
full_name
1
Foo
2
Bar
When these 2 students are created, the shopping cart table automatically becomes:
Shopping cart table
cart_id
1
2
These are my Student and Cart entities.
Student.java
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "student", uniqueConstraints = {
#UniqueConstraint(name = "uc_student_email_address", columnNames = {"email_address"})
public class Student {
#Id
#SequenceGenerator(
name = "student_sequence",
sequenceName = "student_sequence",
allocationSize=1
)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "student_sequence")
private Long studentId;
private String fullName;
#Column(name = "email_address", nullable = false)
private String email;
private String username;
private String password;
ShoppingCart.java
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
public class ShoppingCart {
#Id
private Long cartId;
#OneToOne
#MapsId
#JoinColumn(name = "cart_id", referencedColumnName = "studentId")
private Student student;
So, how do I achieve this?
Thanks in advance.

Related

How to save list of children data in onetomany in Springboot jpa

Parent data is saving but list of children data is not saving in table.
data from postman
{"billno":"nur-1001", "grandTotal": 5000,"billcart":[{"itemcode":"SU10027", "soldPrice":0},{"itemcode":"SU10027","soldPrice":1100}]}
Bill is parent Entity & billcart is child entity
#NoArgsConstructor #AllArgsConstructor #Data #Entity
public class Bill {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String billno;
private Long grandTotal;
#OneToMany(mappedBy = "bill", cascade = CascadeType.ALL)
#JsonIgnore
private List<Billcart> billcart = new ArrayList<>();
public Bill( String billno, Long grandTotal, List<Billcart> billcart) {
this.billno = billno;
this.grandTotal = grandTotal;
this.billcart = billcart;
this.billcart.forEach(e -> e.setBill(this));
}
}
child entity
#NoArgsConstructor #AllArgsConstructor #Data #Entity
public class Billcart {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String itemcode;
private Integer soldPrice;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "bill_id")
private Bill bill;
controller
public void saveBill(#RequestBody Bill request) {
List<Billcart> billscart = request.getBillcart().stream()
.map(e -> new Billcart(e))
.collect(Collectors.toList());
Bill bill = new Bill(request.getBillno(), request.getGrandTotal() , billscart);
billRepository.save(bill);

Spring Data JPA - how to make intermediate query in spring data jpa

I have Promotion, PromotionDetail, Product entities like this:
#Entity
#Table(name = "promotions")
public class Promotion implements Serializable {
#Id
private String id;
#OneToMany(
fetch = FetchType.LAZY,
mappedBy = "promotion",
cascade = CascadeType.ALL
)
private Collection<PromotionDetail> promotionDetails;
}
====
#Entity
#Table(name="product")
public class Product implements Serializable {
#Id
private String id;
#OneToMany(
mappedBy = "product"
)
private Collection<PromotionDetail> promotionDetails;
}
====
#Entity
#Table(name = "promotion_details")
public class PromotionDetail implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne
#JoinColumn(
name = "promotion_id",
referencedColumnName = "id",
nullable = false
)
#JsonIgnoreProperties("promotionDetails")
private Promotion promotion;
#ManyToOne
#JoinColumn(
name = "product_id",
referencedColumnName = "id",
nullable = false
)
#JsonIgnoreProperties({"promotionDetails"})
private Product product;
}
from the above entities i want to find a solution at ProductRepository to get list of Products based on Promotion Id
i tried with line of code like this but it doesn't work:
Page<Product> findProductsByPromotionDetails_Promotion_Id(long id, Pageable pageable);
can someone please help me
it's pretty simple right
Examples of data are as follows:
Product:
id
--------------
P0882021035821
P0882021035822
P0882021035823
P1482022025430
Promotion:
id discount
-------
1 12
2 13
3 12
Promition_Detail
id product_id promiotion_id
1 P0882021035821 1
2 P0882021035823 1
3 P1482022025322 1
4 P1482022025430 5
5 P1482022025322 5
when i execute above query to get list product with promotion _id = 1 I have a product list that has product_id like:
P0882021035821
P0882021035823
P1482022025322
P1482022025322
the issue is i have double product have product id equals P1482022025322
and the result I want is a list like this:
P0882021035821
P0882021035823
P1482022025322
when I execute : findProductsByPromotionDetails_Promotion_Id(1,1);

Spring Boot JPA Using Many-to-Many relationship with additional attributes in the join table

I have two simple classes Student and Course. I am trying to set up many to many relationship between these classes. I want to use additional table whose PRIMARY KEY is the combination of the primary keys of student and course tables (student_id and course_id).
The student class:
#Entity
#Table(name = "student")
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#OneToMany(mappedBy = "student")
private Set<CourseStudent> courses;
}
The course class:
#Entity
#Table(name = "course")
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String courseName;
#OneToMany(mappedBy = "course")
Set<CourseStudent> students;
}
The entity that stores the relationship between course and the student:
#Entity
#NoArgsConstructor
#Data
public class CourseStudent {
#EmbeddedId
CourseStudentKey id;
#ManyToOne
#MapsId("studentId")
#JoinColumn(name = "student_id")
Student student;
#ManyToOne
#MapsId("courseId")
#JoinColumn(name = "course_id")
Course course;
public CourseStudent(Student student, Course course) {
this.student = student;
this.course = course;
this.rating = 0;
}
int rating;
}
Attention: Since I want to have additional features in this entity (for example, storing the rating of the students for courses), I don't want to use #JoinTable idea that we implement in the Student class.
Since I have multiple attributes in the primary key of CourseStudent entity, I used the following class
#Embeddable
#Data
public class CourseStudentKey implements Serializable {
#Column(name = "student_id")
Long studentId;
#Column(name = "course_id")
Long courseId;
}
I have the following POST request to insert the student into a course:
#PostMapping("/insert/students/{studentId}/courses/{courseId}")
public CourseStudent insertStudentIntoCourse(#PathVariable(value = "studentId") Long studentId,
#PathVariable(value = "courseId") Long courseId) {
if (!studentRepository.existsById(studentId)) {
throw new ResourceNotFoundException("Student id " + studentId + " not found");
}
if (!courseRepository.existsById(courseId)) {
throw new ResourceNotFoundException("Course id " + courseId + " not found");
}
CourseStudent courseStudent = new CourseStudent(
studentRepository.findById(studentId).get(),
courseRepository.findById(courseId).get()
);
return courseStudentRepository.save(courseStudent);
}
I have manually added Student and the Course into my local database and send this request by using Postman.
http://localhost:8080/insert/students/1/courses/1
However, I get the following error:
{
"timestamp": "2022-08-04T12:33:18.547+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/insert/students/1/courses/1"
}
In the console, I get NullPointerException. What is the thing I am doing wrong here?

How to make composite Foreign Key part of composite Primary Key with Spring Boot - JPA

I have a problem with the historization of objects in the database.
the expected behavior of the save JpaRepository method is : Insert in the two tables idt_h and abo_h
But the current behavior is Insert in the idt_h table and update in the abo_h table.
#Data
#Entity
#Table(name = "ABO_H")
#AllArgsConstructor
#NoArgsConstructor
public class AboOP {
#Id
#Column(name = "ABO_ID")
private String id;
#Column(name = "ABO_STATUT")
private String statut;
#Column(name = "ABO_DATE_STATUT")
private Instant date;
#Column(name = "ABO_CoDE")
private String code;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "IDC_ID", referencedColumnName = "IDC_ID"),
#JoinColumn(name = "DATE_HISTO", referencedColumnName = "DATE_HISTO")
})
private IdtOP idtOP;
}
#Data
#Entity
#Table(name = "IDT_H")
#AllArgsConstructor
#NoArgsConstructor
public class IdtOP {
#AttributeOverrides({
#AttributeOverride(name = "id",
column = #Column(name = "IDC_ID")),
#AttributeOverride(name = "dateHisto",
column = #Column(name = "DATE_HISTO"))
})
#EmbeddedId
private IdGenerique idtId = new IdGenerique();
//Other fields
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Embeddable
public class IdGenerique implements Serializable {
private String id;
private Instant dateHisto;
}
I think that the class IdGenerique which groups the id and dateHisto is not well invoked for the table abo_h ??
thanks in advance
When you use the save() method, entityManager checks if the entity is new or not. If yes, the entity will be saved, if not, it'll be merged
If you implement your Entity Class with the inteface Persistable, you can override the method isNew() and make it returns True. In that case the save() method will persist, and not merge, your entity.

JPA Composite PK referenced by FKs in One to Many Relationship

I am trying to map the tables below into JPA. The relationships are one-to-many between user_tax and tax and user_tax and user. It has confused me the fact that i have a composite primary key, and i need to map the foreign keys to these 2 keys.
the error message: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: entity.Tax.user_tax in entity.UserTax.taxs
tax user_tax user
-------- -------- ------
PK|t_id |--------| t_id |PK-FK |u_name|
|t_name| PK-FK| u_id |-------|u_id | PK
| | | name | | |
Here is my Entities:
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="u_name")
private String uname;
getters + setters
}
#Entity
#Table(name = "tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Tax implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "t_name")
private String tname;
#Embeddable
public class UserTaxId implements Serializable {
#Column(name="u_id")
private Long uId;
#Column(name="t_id")
private Long tId;
#Entity
#Table(name = "user_tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserTax implements Serializable {
#EmbeddedId
private UserTaxId userTaxId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user_tax")
private List<User> users;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user_tax")
private List<Tax> taxs;
Your 1:n mappings are backwards (i.e. a UserTax can have only a single User and a single Tax) and you are using a derived identity. Try mapping UserTax like this:
#Entity
#Table(name = "user_tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserTax implements Serializable {
#EmbeddedId
private UserTaxId userTaxId;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("uId") // maps uId attribute of embedded id
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("tId") // maps tId attribute of embedded id
private Tax tax;
...
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
I will post here what worked for me after 3 days of research.
Brian Vosburgh correctly posted the UserTax class:
#Entity
#Table(name = "user_tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserTax implements Serializable {
#EmbeddedId
private UserTaxId userTaxId;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("uId") // maps uId attribute of embedded id
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("tId") // maps tId attribute of embedded id
private Tax tax;
...
}
However, i was getting error meassages and my code wasn't compiling. Then i also had to edit the User and Tax classes:
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(
mappedBy = "tid",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserTax> tax = new ArrayList<>();
#Column(name="u_name")
private String uname;
getters + setters
}
#Entity
#Table(name = "tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Tax implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(
mappedBy = "uid",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserTax> taxs = new ArrayList<>();
#Column(name = "t_name")
private String tname;
setters+getters
}
Here is the link where i found the solution to my problem: https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/

Resources