Я создаю приложение Spring Boot с использованием Crud Repository. У меня проблема с созданием отношений «многие ко многим». Проблема возникает, когда я хочу добавить новую запись в сущность Learning, которая должна принадлежать существующей записи в сущности Student. Ошибка выглядит следующим образом:
Ошибка обработки запроса; вложенным исключением является org.springframework.dao.InvalidDataAccessApiUsageException: отдельная сущность передана для сохранения: pl.anitakowalczyk.surwejlansapi.dao.entity.Student; Вложенное исключение: org.hibernate.PersistentObjectException: отдельная сущность передана для сохранения: pl.anitakowalczyk.surwejlansapi.dao.entity.Student
Это код, который представляет сохранение этой новой записи в базе данных:
Course course = courseRepository.findById(courseId).get();
Student student = currentUser;
Integer percent = points * 100 / allPoints;
Learning learning = new Learning(course, percent);
learning.setStudent(student);
learningRepository.save(learning);
Что я делаю не так?
Вот схема базы данных: ERD
Студент. java
package pl.anitakowalczyk.surwejlansapi.dao.entity;
import lombok.Data;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Data
@Entity
public class Student {
private Integer studentid;
private String imie;
private String nazwisko;
private String login;
private String password;
private List<Learning> learnings = new ArrayList<Learning>();
public Student() {
}
public Student(String imie, String nazwisko, String login, String password) {
this.imie = imie;
this.nazwisko = nazwisko;
this.login = login;
this.password = password;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getStudentid() {
return studentid;
}
public void setStudentid(Integer studentid) {
this.studentid = studentid;
}
public String getImie() {
return imie;
}
public void setImie(String imie) {
this.imie = imie;
}
public String getNazwisko() {
return nazwisko;
}
public void setNazwisko(String nazwisko) {
this.nazwisko = nazwisko;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@OneToMany(mappedBy = "student", cascade = CascadeType.ALL)
public List<Learning> getLearnings() {
return learnings;
}
public void setLearnings(List<Learning> learnings) {
this.learnings = learnings;
}
}
Обучение. java
package pl.anitakowalczyk.surwejlansapi.dao.entity;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Data
@Entity
public class Learning implements Serializable {
private Integer learningid;
private Student student;
private Course course;
private int progress;
private Date date;
public Learning() {
}
public Learning(Student student, Course course, int progress) {
this.student = student;
this.course = course;
this.progress = progress;
this.date = new Date();
}
public Learning(Course course, int progress) {
this.course = course;
this.progress = progress;
this.date = new Date();
}
@Id
@GeneratedValue
@Column(name = "learningid")
public Integer getLearningid() {
return learningid;
}
public void setLearningid(Integer learningid) {
this.learningid = learningid;
}
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "studentid")
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "courseid")
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
@Column(name = "date")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
проверка. jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Aplikacja FISZKI</title>
<link rel="stylesheet" href="https://unpkg.com/swiper/css/swiper.css">
<link rel="stylesheet" href="https://unpkg.com/swiper/css/swiper.min.css">
</head>
<body>
<div class="container">
<div class="header">Kurs <span style="font-weight: 600">${courseName}</span></div>
<div class="words">
<c:choose>
<c:when test="${empty words}">
<div class="empty">
Ten kurs nie posiada jeszcze żadnych słów do nauki.
</div>
</c:when>
<c:otherwise>
<div class="swiper-container">
<div class="swiper-wrapper">
<c:forEach items="${words}" var="word">
<div class="swiper-slide">
<div>
<fieldset class="word">
<legend>Polskie znaczenie</legend>
<div >${word.polish}</div>
</fieldset>
</div>
<div>
<fieldset id="eng${word.wordid}field" class="word">
<legend>Angielskie znaczenie</legend>
<textarea id="eng${word.wordid}" rows="1" cols="20"></textarea>
<button onclick="checkEnglish('eng${word.wordid}', '${word.english}')" style="margin: 0px;" id="sprawdz" type="button">Sprawdź</button>
</fieldset>
</div>
</div>
</c:forEach>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>
</c:otherwise>
</c:choose>
<div class="buttonlist">
<div class="zakoncz">
<form id="form" method="post" action="">
<button id="zakoncz" type="button" onclick="countPoints(${fn:length(words)}, ${courseId})">Zakończ</button>
</form>
</div>
<div class="buttony">
<a href="http://localhost:8090/fiszki/login?logout=1">
<button type="submit" name="submit" value="buttonname" id="wyloguj">Wyloguj</button>
</a>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/swiper/js/swiper.min.js"></script>
<script>
var swiper = new Swiper('.swiper-container', {
pagination: {
el: '.swiper-pagination',
type: 'progressbar',
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
}
});
function checkEnglish(engId, englishMeaning) {
if(document.getElementById(engId).value === englishMeaning) {
document.getElementById(engId + "field").style.border = "1px solid #00b300";
document.getElementById(engId + "field").setAttribute("point", "1");
} else {
document.getElementById(engId + "field").style.border = "1px solid #cc0000";
}
};
function countPoints(totalPoints, courseID) {
if(totalPoints === 0 ) {
window.location = "http://localhost:8090/fiszki/courses";
} else {
var points = 0;
if(document.querySelectorAll('[point]')) {
document.querySelectorAll('[point]').forEach(function(item){
points++;
})
}
document.querySelector("form").action = "/fiszki/finishTest/" + courseID + "/" + points + "/" + totalPoints;
document.forms["form"].submit();
return points;
}
};
</script>
</body>
</html>