Java Quarkus:列表中存在重复条目<;课程>;同一实体对象的
我目前正在进行一个学校项目,该项目允许用户将音频课程添加到他们的图书馆,并收听每门课程的课程。我将试着用一个例子来解释这个问题: 当我使用POST请求创建一个新的课程实体时,还没有添加任何课程。 创建课程后,我还通过POST请求将课程添加到课程中。 因此,我的数据库(PostgreSQL)在课程表中有一个条目,在课程表中有两个条目 和一个连接这两者的参考表(hibernate生成) 当我尝试向用户添加课程时,问题就出现了。它在添加课程时不会抛出警告或期望,而在用户合并后的结果也会提供期望的结果:Java Quarkus:列表中存在重复条目<;课程>;同一实体对象的,java,postgresql,rest,jpa,quarkus,Java,Postgresql,Rest,Jpa,Quarkus,我目前正在进行一个学校项目,该项目允许用户将音频课程添加到他们的图书馆,并收听每门课程的课程。我将试着用一个例子来解释这个问题: 当我使用POST请求创建一个新的课程实体时,还没有添加任何课程。 创建课程后,我还通过POST请求将课程添加到课程中。 因此,我的数据库(PostgreSQL)在课程表中有一个条目,在课程表中有两个条目 和一个连接这两者的参考表(hibernate生成) 当我尝试向用户添加课程时,问题就出现了。它在添加课程时不会抛出警告或期望,而在用户合并后的结果也会提供期望的结果:
HTTP/1.1 200 OK
Content-Length: 674
Content-Type: application/json
{
"courses": [
{
"description": "A memoir by the creator of NIKE",
"id": 2,
"lessons": [
{
"audioUrl": "http://localhost:8080",
"description": "A Tutorial on how to create your own Audally's",
"duration": "00:12:54",
"id": 1,
"name": "TutorialNr2"
},
{
"audioUrl": "http://localhost:8080",
"description": "A Tutorial on how to create your own Audally's",
"duration": "00:12:54",
"id": 2,
"name": "TutorialNr1"
}
],
"name": "Shoe Dog - Phil Knight",
"pictureUrl": "https://images.unsplash.com/photo-1556906781-9a412961c28c?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80"
}
],
"email": "jane@doe.co",
"id": 2,
"password": "password",
"subscriptions": [],
"userName": "jane"
}
Response code: 200 (OK); Time: 80ms; Content length: 674 bytes
但在我再次请求获取用户的所有信息后,我得到的是:
{
"courses": [
{
"description": "A memoir by the creator of NIKE",
"id": 2,
"lessons": [
{
"audioUrl": "http://localhost:8080",
"description": "A Tutorial on how to create your own Audally's",
"duration": "00:12:54",
"id": 1,
"name": "TutorialNr2"
},
{
"audioUrl": "http://localhost:8080",
"description": "A Tutorial on how to create your own Audally's",
"duration": "00:12:54",
"id": 2,
"name": "TutorialNr1"
}
],
"name": "Shoe Dog - Phil Knight",
"pictureUrl": "https://images.unsplash.com/photo-1556906781-9a412961c28c?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80"
},
{
"description": "A memoir by the creator of NIKE",
"id": 2,
"lessons": [
{
"audioUrl": "http://localhost:8080",
"description": "A Tutorial on how to create your own Audally's",
"duration": "00:12:54",
"id": 1,
"name": "TutorialNr2"
},
{
"audioUrl": "http://localhost:8080",
"description": "A Tutorial on how to create your own Audally's",
"duration": "00:12:54",
"id": 2,
"name": "TutorialNr1"
}
],
"name": "Shoe Dog - Phil Knight",
"pictureUrl": "https://images.unsplash.com/photo-1556906781-9a412961c28c?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80"
}
],
"email": "jane@doe.co",
"id": 2,
"password": "password",
"subscriptions": [],
"userName": "jane"
}
Response code: 200 (OK); Time: 50ms; Content length: 1247 bytes
它只显示课程乘以课程的课程数。在这种情况下,有两个教训。
如果我要添加另一个课程,那么它会像这样继续下去,即使在数据库中没有对此的多个引用
以下是我使用的代码:
@Path("/courses")
@Produces(APPLICATION_JSON)
@Transactional
@ApplicationScoped
public class CourseResource {
@Inject
CourseRepository courseRepository;
@GET
public List<Course> getAll(){
return courseRepository.findAll().list();
}
@POST
public Response addCourse(Course course){
if(courseRepository.findAll().stream().anyMatch(course1 ->
course1.name.equals(course.name) &&
course1.description.equals(course.description) &&
course1.lessons.equals(course.lessons))){
return Response
.status(406,"Course already exists!")
.build();
}
Course entry = new Course();
entry.copyProperties(course);
courseRepository.persist(entry);
return Response.ok(entry).build();
}
}
起初,我认为课程和课程是双向的,认为这导致了问题,我把它改成了单向的,因为只有课程知道课程和课程
只知道自己,但这并没有解决问题
package com.audally.backend.entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import org.jboss.resteasy.spi.touri.MappedBy;
import javax.annotation.processing.Generated;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "users",schema = "audally")
public class User implements Serializable {
@Id
@SequenceGenerator(
name = "userSequence",
sequenceName = "user_id_seq",
initialValue = 3,
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.IDENTITY
,generator = "userSequence")
public Long id;
@NotNull
@NotEmpty(message = "Not allowed to be empty!")
public String userName;
@NotNull
@Email
public String email;
@NotNull
@NotEmpty
public String password;
/*
@NotNull
public Date joinDate;
*/
@OneToMany(mappedBy = "user")
public List<Subscription> subscriptions = new ArrayList<Subscription>();
@ManyToMany(fetch = FetchType.EAGER)
public List<Course> courses = new ArrayList<Course>();
public User(){ }
public void copyProperties(User user) {
this.email = user.email;
this.subscriptions = user.subscriptions;
this.courses = user.courses;
this.userName = user.userName;
this.password = user.password;
}
public void addCourses(Course courses) {
this.courses.add(courses);
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
", subscriptions=" + subscriptions.toArray().toString() +
", courses=" + courses.toArray().toString() +
'}';
}
}
package com.audaly.backend.entity;
导入io.quarkus.hibernate.orm.panache.PanacheEntity;
导入org.jboss.resteasy.spi.touri.MappedBy;
导入javax.annotation.processing.Generated;
导入javax.persistence.*;
导入javax.validation.constraints.Email;
导入javax.validation.constraints.NotEmpty;
导入javax.validation.constraints.NotNull;
导入java.io.Serializable;
导入java.util.ArrayList;
导入java.util.Date;
导入java.util.List;
@实体
@表(name=“users”,schema=“audaly”)
公共类用户实现可序列化{
@身份证
@序列发生器(
name=“userSequence”,
sequenceName=“用户id顺序”,
初始值=3,
allocationSize=1
)
@生成值(
策略=GenerationType.IDENTITY
,generator=“userSequence”)
公共长id;
@NotNull
@NotEmpty(message=“不允许为空!”)
公共字符串用户名;
@NotNull
@电子邮件
公共字符串电子邮件;
@NotNull
@空空如也
公共字符串密码;
/*
@NotNull
公开日期;
*/
@OneToMany(mappedBy=“用户”)
公共列表订阅=新建ArrayList();
@ManyToMany(fetch=FetchType.EAGER)
public List courses=new ArrayList();
公共用户(){}
公共void copyProperties(用户){
this.email=user.email;
this.subscriptions=user.subscriptions;
this.courses=user.courses;
this.userName=user.userName;
this.password=user.password;
}
公共课程(课程){
本.课程.添加(课程);
}
公共字符串getUserName(){
返回用户名;
}
public void setUserName(字符串用户名){
this.userName=用户名;
}
公共字符串getEmail(){
回复邮件;
}
公用电子邮件(字符串电子邮件){
this.email=电子邮件;
}
公共字符串getPassword(){
返回密码;
}
public void setPassword(字符串密码){
this.password=密码;
}
公开课程名单{
返回课程;
}
公共课程(列出课程){
本课程=课程;
}
@凌驾
公共字符串toString(){
返回“用户{”+
“id=”+id+
“,userName='”+userName+'\''+
“,email='”+email+'\''+
,password=''+password+'\''+
“,subscriptions=“+subscriptions.toArray().toString()+
“,courses=“+courses.toArray().toString())+
'}';
}
}
如果我遗漏了什么或者有人想知道什么,我很乐意提供。
我只想要这个奇怪的虫子?离开,让我的代码完成它应该做的工作…在朋友的帮助下解决了这个问题 对于任何想知道的人来说,问题是我使用的是FetchType.earge而不是Lazy
这导致显示了多个课程。每次增加一节新课时,它可能都会取消课程,这就是事情的结局。欢迎收看StackOverflow!:)如果我理解正确的话,那么基本的问题是您正在执行多个
GET
请求,但每次的答案都不同——即课程重复。正确吗?thx^^,不一定,因此,当我执行加载到用户课程中的get请求时,它会显示JSON数组课程内的课程乘以该课程的课程数。换句话说。是和否?将课程添加到用户后会显示正确答案(返回response.ok(userRepository.findById(uid)).build();)的响应),但当我尝试获取用户时,它将显示重复的课程,如果我向课程添加更多课程,它将显示更多重复的课程。。
package com.audally.backend.boundary;
import io.quarkus.security.identity.SecurityIdentity;
import org.jboss.resteasy.annotations.cache.NoCache;
import javax.annotation.security.RolesAllowed;
import com.audally.backend.control.CourseRepository;
import com.audally.backend.control.UserRepository;
import com.audally.backend.entity.Course;
import com.audally.backend.entity.User;
import org.jose4j.json.internal.json_simple.JSONObject;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.json.bind.annotation.JsonbTransient;
import javax.transaction.Transactional;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@Path("/users")
@Produces(APPLICATION_JSON)
@Transactional
@ApplicationScoped
public class UserResource {
@Inject
UserRepository userRepository;
@Inject
CourseRepository courseRepository;
@JsonbTransient
private JSONObject businessuser;
@GET
@Path("/{UserId}")
public Response getUser(@PathParam("UserId") Long uid){
return Response.ok(userRepository.findById(uid)).build();
}
@GET
@Path("/{UserId}/courses")
public Response getCoursesOfUser(@PathParam("UserId") Long uid){
User user = userRepository.findById(uid);
if(user == null){
return Response
.status(202,"Course already exists in the User!")
.build();
}
businessuser = new JSONObject();
businessuser.merge("courses",user.courses.stream().filter(distinctByKey(course -> course.name))
.collect(Collectors.toList()),(o, o2) -> o = o2);
return Response.ok(businessuser.get("courses")).build();
}
@POST
@Path("{UserId}/courses/{CourseId}")
public Response addCourseToUser(@PathParam("UserId") Long uid
,@PathParam("CourseId") Long cid){
User user = userRepository.findById(uid);
Course course = courseRepository.findById(cid);
if(user.courses.contains(course)){
return Response
.status(406,"Course already exists in the User!")
.build();
}
if(user == null){
return Response
.status(204,"User was not found!")
.build();
}
else if(course == null){
return Response
.status(204,"Course was not found!")
.build();
}
user.addCourses(course);
userRepository.getEntityManager().merge(user);
return Response.ok(userRepository.findById(uid)).build();
}
@POST
@Transactional
@Path("addUser")
public Response addUser(User user){
User entry = new User();
if(userRepository.find("email",user.email).count() == 1){
return Response
.status(406,"User email already exists!")
.build();
}
entry.copyProperties(user);
userRepository.persist(entry);
return Response.ok(entry).build();
}
public static <T> Predicate<T> distinctByKey(
Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
package com.audally.backend.entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import org.hibernate.validator.constraints.URL;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.transaction.Transactional;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "courses",schema = "audally")
public class Course implements Serializable {
@Id
@SequenceGenerator(
name = "courseSequence",
sequenceName = "course_id_seq",
initialValue = 4,
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.IDENTITY
,generator = "courseSequence")
public Long id;
@NotNull
public String name;
@Size(max = 400)
public String description;
@URL
public String pictureUrl;
@OneToMany(fetch = FetchType.EAGER)
public List<Lesson> lessons = new ArrayList<Lesson>();
public Course(){
}
public void addLessons(Lesson lesson){
this.lessons.add(lesson);
}
public List<Lesson> getLessons(){
return this.lessons;
}
public void copyProperties(Course course) {
this.name = course.name;
this.lessons = course.lessons;
this.description = course.description;
this.pictureUrl = course.pictureUrl;
}
}
package com.audally.backend.entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import org.hibernate.validator.constraints.URL;
import javax.json.bind.annotation.JsonbDateFormat;
import javax.json.bind.annotation.JsonbTransient;
import javax.persistence.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.sql.Time;
import java.time.LocalTime;
@Entity
@Table(name = "lessons",schema = "audally")
public class Lesson implements Serializable {
@Id
@SequenceGenerator(
name = "lessonSequence",
sequenceName = "lesson_id_seq",
initialValue = 1,
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.IDENTITY
,generator = "lessonSequence")
public Long id;
@NotNull
public String name;
@Size(max = 400)
public String description;
@URL
public String audioUrl;
@JsonbDateFormat("HH:mm:ss")
public LocalTime duration;
/*@ManyToOne
@JsonbTransient
@JoinColumn(name = "course_id")
public Course course;
*/
public void copyProperties(Lesson lesson) {
this.name = lesson.name;
this.duration = lesson.duration;
this.audioUrl = lesson.audioUrl;
this.description = lesson.description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getAudioUrl() {
return audioUrl;
}
public void setAudioUrl(String audioUrl) {
this.audioUrl = audioUrl;
}
public LocalTime getDuration() {
return duration;
}
public void setDuration(LocalTime duration) {
this.duration = duration;
}
/*
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}*/
}
package com.audally.backend.entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import org.jboss.resteasy.spi.touri.MappedBy;
import javax.annotation.processing.Generated;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "users",schema = "audally")
public class User implements Serializable {
@Id
@SequenceGenerator(
name = "userSequence",
sequenceName = "user_id_seq",
initialValue = 3,
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.IDENTITY
,generator = "userSequence")
public Long id;
@NotNull
@NotEmpty(message = "Not allowed to be empty!")
public String userName;
@NotNull
@Email
public String email;
@NotNull
@NotEmpty
public String password;
/*
@NotNull
public Date joinDate;
*/
@OneToMany(mappedBy = "user")
public List<Subscription> subscriptions = new ArrayList<Subscription>();
@ManyToMany(fetch = FetchType.EAGER)
public List<Course> courses = new ArrayList<Course>();
public User(){ }
public void copyProperties(User user) {
this.email = user.email;
this.subscriptions = user.subscriptions;
this.courses = user.courses;
this.userName = user.userName;
this.password = user.password;
}
public void addCourses(Course courses) {
this.courses.add(courses);
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
", subscriptions=" + subscriptions.toArray().toString() +
", courses=" + courses.toArray().toString() +
'}';
}
}