Spring DataJPA not saving 3rd tabledata to the database - database

I have no problem with saving my entities to the database. However when I try to insert values into my 3rd many-to-many table, it simply doesn't do anything.
Here is my student entity;
#Table(name = "student", schema = "school")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long studentId;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "student_classroom", schema = "school")
private Collection<Classroom> classroom = new ArrayList<>();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "student_teacher",
joinColumns = {
#JoinColumn(name = "student_id", referencedColumnName = "studentId",
nullable = false, updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "teacher_id", referencedColumnName = "teacherId",
nullable = false, updatable = false)})
private Set<Teacher> teachers = new HashSet<>();
The teacher entity.
#Entity
#Table(name = "teacher", schema = "school")
public class Teacher {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long teacherId;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "teacher_classroom", schema = "school")
private Collection<Classroom> classroom = new ArrayList<>();
#ManyToMany(mappedBy = "teachers", fetch = FetchType.LAZY)
private Set<Student> students = new HashSet<>();
Here is my service method.
public void addTeacherToStudent(long teacherId, long studentId) {
Optional<Teacher> teacher = teacherRepository.findById(teacherId);
Optional<Student> student = studentRepository.findById(studentId);
student.get().getTeachers().add(teacher.get());
teacher.get().getStudents().add(student.get());
}
It has no problem saving the teachers and students in the sets in memory, however it doesn't reach the database. I have tried every annotation, didn't work.

Try adding this in Teacher entity
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "student_teacher",
joinColumns = #JoinColumn(name = "teacher_id"),
inverseJoinColumns = #JoinColumn(name = "student_id")
)
private Set<Student> students = new HashSet<>();

Related

Resolved [org.springframework.dao.DataIntegrityViolationException: could not execute statement

package com.codedecode.demo.entity;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name = "users")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "email", unique = true, length = 100)
private String email;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<CV> cv;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<JobApplication> jobApplication;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<CurriculumVitae> curriculumVitae;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<CoverLetter> coverLetter;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "users_roles", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "address_id", referencedColumnName = "id")
#ToString.Exclude
#JsonIgnore
private Address address;
#Column(name = "password")
private String password;
#Column(name = "birth_date")
private Date birthDate;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "career_goals")
private String careerGoals;
#Column(name = "university")
private String university;
#Column(name = "rating")
private String rating;
#Column(name = "phone")
private String phone;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Notification> notifications;
#Column(name = "maria_status")
private String mariaStatus;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Degree> degrees;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Posting> postings;
#Column(name = "gender")
private String gender;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Language> languages;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Experience> experiences;
#Column(name = "taxt_number")
private Long taxtNumber;
#Column(name = "images")
private String images;
#Column(name = "candidate_cv")
private String candidateCV;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "desired_job_id", referencedColumnName = "id")
private DesiredJob desiredJob;
#OneToMany(mappedBy = "candidate", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Message> candidateMessage;
#OneToMany(mappedBy = "recruiter", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Message> recruiterMessage;
// #OneToOne(fetch = FetchType.LAZY, optional = false)
// #JoinColumn(name = "candidate_profile_save_id", referencedColumnName = "id")
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#ToString.Exclude
#JsonIgnore
private CandidateProfileSaved candidateProfileSaved;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#ToString.Exclude
#JsonIgnore
private Collection<SavedJob> savedJob;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<AppliedJob> appliedJob;
public User(Long id, String email) {
this.id = id;
this.email = email;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("User [id=");
builder.append(id);
builder.append(", email=");
builder.append(email);
builder.append(", address=");
builder.append(address);
builder.append(", password=");
builder.append(password);
builder.append(", name=");
builder.append(name);
builder.append("]");
return builder.toString();
}
}
I don't know why when I try to insert more users to database from postman call api then I have an error is : "Violation of UNIQUE KEY constraint 'UK_hbvhqvjgmhd5omxyo67ynvbyp'. Cannot insert duplicate key in object 'dbo.users'. The duplicate key value is (1)."
Why primary key of users is not increment ?
Table already have identity in its id column. So, maybe, Hiberante must be enabling IDENTITY_INSERT option and trying reinsert de row.
create database [DATABASE_NAME] COLLATE Latin1_General_100_BIN2_UTF8;

JPQL with Group by clause in SQL Server database not working

I am new to SQL Server database. The below JPQL query is not getting executed and not throwing any errors. Just my application hanging over at this query. This code is working fine with MySQL database, but not with SQL Server(2019) database.
#Query(value = "SELECT R.riskType, count(distinct V.bname) FROM RiskViolation V JOIN V.job J JOIN V.risk R WHERE J.id = ?1 GROUP BY R.riskType ")
public List<Object[]> sodUserByRiskType(Long jobId);
But when I run the below converted sql query directly in the SQL Server database, it is working fine.
select count(distinct riskviolat0_.bname) as col_1_0_, risklog2_.risk_type as col_0_0_ from risk_violation riskviolat0_ inner join analysis_job analysisjo1_ on riskviolat0_.job_id=analysisjo1_.id inner join risk_log risklog2_ on riskviolat0_.risk_id=risklog2_.id where analysisjo1_.id=? group by risklog2_.risk_type;
Here are the Java entity classes which are used in JPQL query:
RiskViolation.java
#Entity
#Table(name = "risk_violation")
public class RiskViolation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "job_id")
private AnalysisJob job;
private String bname;
private String riskName;
private String violations;
#Column(name = "violated", columnDefinition = "BIT", length = 1)
private boolean violated;
#Column(name = "simulation", columnDefinition = "BIT", length = 1)
private boolean simulation;
#Column(name = "mitigation_name")
private String mitigationName;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "risk_id")
private RiskLog risk;
#JsonIgnore
#OneToMany(mappedBy = "riskViolation", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<RuleViolation> ruleViolations;
}
AnalysisJob.java
#Entity
#Table(name = "analysis_job")
public class AnalysisJob {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "profile_name")
private String profileName;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "profile_id")
#OnDelete(action = OnDeleteAction.CASCADE)
private AnalysisProfileLog profileLog;
#Column(name = "description")
private String description;
#Column(name = "status")
private String status;
#Column(name = "started_on")
private Date startedOn;
#Column(name = "completed_on")
private Date completedOn;
#Column(name = "completion_message")
private String completionMessage;
#Column(name = "percent_completed")
private float percentCompleted;
#Column(name = "run_by")
private String runBy;
#Column(name = "removed", columnDefinition = "BIT", length = 1)
private boolean removed;
#OneToMany(mappedBy = "job", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<JobResultData> resultData;
#Column(name = "pos_analysis", columnDefinition = "BIT", length = 1)
private boolean posAnalysis;
#Column(name = "submitted", columnDefinition = "BIT", length = 1)
private boolean submitted;
#Column(name = "position_id")
private String positionId;
}
RiskLog.java
#Entity
#Table(name = "risk_log")
public class RiskLog {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long jobId;
private String name;
private String riskDescription;
private String riskCondition;
private String businessProcess;
#Column(name = "business_sub_process")
private String subProc;
private String riskType;
#JsonIgnore
#OneToMany(mappedBy = "riskLog", cascade = CascadeType.ALL)
protected List<RuleLog> rules;
}
Do I need to make any changes to the query and entity classes to make it work?
Here is Query Plan URL
Estimated Execution Plan
Actual Execution Plan
Query Plan with Actual Rows
It worked after avoiding facade class between Java class (where my business logic resides) and JPA repository( use to execute JPQL queries). Directly invoked JPA repository method from Java class. Not sure why it did not work with facade class with SQL Server, but same worked with MySQL database.

Hibernate cascade parent child when using sql server spatial dialect

I am using spring boot data jpa with SQLServer and spatial dialect as below:
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect
Parent Class:
#Entity
#Table(name = "users", schema = "dbo")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinTable(name = "users_roles",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id"))
private Collection<Role> roles = new ArrayList<>();
}
Child Class:
#Entity
#Table(name = "roles", schema = "dbo")
public class Role {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#ManyToMany(mappedBy="roles", cascade = {CascadeType.ALL})
private Collection<User> users = new ArrayList<>();
}
on saving user:
u.setRoles(roles);
userRepository.save(u);
but alyways get user_id equals zero on table users_roles
please help
Note that SpatialDialect is needed to manage spatial data on other entities.

Bridge table primary as foreign key in another table (JPA)

I'm designing a student enrollment database
Student-Table
student_id (pk)
//other attributes
Course-Table
course_id (pk)
//other attributes
Student_course-Table
student_course_id(pk)
course_id (fk)
student_id (fk)
Lectrue-Table
lecture_id(pk)
student_course_id(fk - > student_course table)
// other attributes
Basically I want to store which student is enrolled to which course and has attend how many lectures for that particular course.
Q1 ) Is this design correct? Should I use primary key of Bridge table as foreign key in another table.
Q2 ) I did manyToMany mapping between student <-> course and oneToMany between student_course <-> lecture and got the following error :
org.hibernate.MappingException: Foreign key must have same number of columns as the referenced primary key
Any idea how to proceed?
//UPDATE Entity class
#Entity
#Table(name = "STUDENT")
public class Student implements Serializable {
#Id
#Column(name = "STUDENT_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToMany(mappedBy = "students" ,cascade = CascadeType.ALL)
#MapKey(name = "courseName")
private Map<String, Course> courses;
}
#Entity
#Table(name = "COURSE", uniqueConstraints = #UniqueConstraint(columnNames = {"COURSE_NAME"}))
public class Course implements Serializable {
#Id
#Column(name = "COURSE_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "STUDENT_COURSE", joinColumns = {
#JoinColumn(name = "COURSE_ID") }, inverseJoinColumns = {
#JoinColumn(name = "STUDENT_ID") })
private Set<Student> students;
#Column(name = "COURSE_NAME")
private String courseName;
}
#Entity
#Table(name = "LECTURE")
public class Lecture {
#Id
#Column(name = "LECTURE_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "STUDENT_COURSE_ID")
private StudentCourse studentCourse;
}
#Entity
#Table(name = "STUDENT_COURSE")
public class StudentCourse {
#Id
#Column(name = "STUDENT_COURSE_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "STUDENT_ID")
private Long studentId;
#Column(name = "COURSE_ID")
private Long courseId;
#OneToMany(mappedBy = "studentCourse")
private Set<Lecture> lectures = new HashSet<Lecture>();
}

Updating multiple tables when saving entity Spring MVC Angular

I have a problem with saving entity with references to database using
Spring MVC and AngularJS.
My entities:
Entity
#Table(name = "comment")
public class Comment {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "creation_date", nullable = false)
private Date creationDate;
#Column(name = "comment", nullable = false)
private String comment;
#ManyToOne
#JoinColumn(name = "article", nullable = false)
private Article article;
#ManyToOne
#JoinColumn(name = "user", nullable = false)
private User user;
}
#Entity
#Table(name = "article")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne
#JoinColumn(name="user", nullable=false)
private User user;
...
}
How can I save new Article but at the same time add new entity to Comment table?
How can two updates be performed in one transaction?
How sholud I connect request from angular with controller, and how sholud they look?
Angular:
$http({
url : ..../new,
method : POST,
data : ?
})
#RestController
#RequestMapping(value = "/new", method = RequestMethod.POST)
public Article addArticle(#RequestBody Article article, ?) {
article.setId(null);
return articleService.save(article);
//but how to save comment?
}
Thank You!

Resources