简体   繁体   English

如何在 Spring JPA 中将一个实体与多个实体连接?

[英]How to connect one entity with more than one entity in Spring JPA?

I have some problems in understanding how to connect one entity with others in one attribute.我在理解如何在一个属性中将一个实体与其他实体联系起来时遇到了一些问题。 That is not typical OneToMany relationship, I'm talking about situation when I need to implement complains functionality in my application: User can complain about several different entities ( Question , Answer , Comment or another User ), so the Complain entity will have schema relations like:这不是典型的 OneToMany 关系,我说的是我需要在我的应用程序中实现投诉功能的情况: User可以投诉几个不同的实体( QuestionAnswerComment或另一个User ),因此Complain实体将具有模式关系像: 图式

where User connects as One to many to user_id and Many To One to entity_id ( 1 to * and * to 1 in image).其中 User 连接为一对多到user_id ,多对一连接到entity_id (图像中的1**1 )。

So, I tried to use parameterized class Complain to implement this ( BaseComplain is empty class):所以,我尝试使用参数化的 class Complain来实现这个( BaseComplain是空类):

Complain.java

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name = "complains")
public class Complain<T extends BaseComplain> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;


    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user_id;

    @ManyToOne
    @JoinColumn(name = "entity_id", nullable = false)
    private T entity_id;

    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date created_on;

}

User.java

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name = "users")
public class User extends BaseComplain {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany(mappedBy = "user_id", orphanRemoval = true, fetch = FetchType.LAZY)
    @ToString.Exclude
    private Set<Complain<BaseComplain>> author_complains;

    @OneToMany(mappedBy = "entity_id", orphanRemoval = true, fetch = FetchType.LAZY)
    @ToString.Exclude
    private Set<Complain<User>> complains;

    <...other stuff...>
}

And Question.java (all entities have the same realisation of relationship):Question.java (所有实体具有相同的关系实现):

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@Table(name = "questions")
public class Question extends BaseComplain {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "entity_id", orphanRemoval = true, fetch = FetchType.LAZY)
    @ToString.Exclude
    @JsonManagedReference
    private Set<Complain<Question>> complains;
    
    <...other stuff...>
}

But it caused (formatted):但它导致(格式化):

org.hibernate.AnnotationException: 
Property com.*.*.Entities.Complain.entity_id has an unbound type and no explicit target entity.
Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=)
or use an explicit @Type...

I can add all stack trace, but there are only typical spring app exceptions ( Bean creation error , embedded Tomcat exception ).我可以添加所有堆栈跟踪,但只有典型的 spring 应用程序异常( Bean creation errorembedded Tomcat exception )。

So the question is - Is there any way to implement this logics using only, like, "basic" features of JPA?所以问题是——有没有办法只使用 JPA 的“基本”功能来实现这个逻辑?

Probably, I have some ideas of @MappedSuperclass usage, but still need your help.可能,我对@MappedSuperclass的用法有一些想法,但仍然需要您的帮助。

How about this - it looks like what you have tried to a certain extent;这个怎么样——看起来你在一定程度上已经尝试过了; the idea is that the Complaint is an abstract base entity, so that it can have relations to and from it, but the concrete implementations are questions, answers etc. To have a base table and separate ones per complaint type, use @Inheritance(strategy = InheritanceType.JOINED) .这个想法是Complaint是一个抽象的基本实体,因此它可以与它有关系,但具体的实现是问题,答案等。要有一个基表和每个投诉类型分开的基表,请使用@Inheritance(strategy = InheritanceType.JOINED) And use concrete complaint types that are different from the entities they link to, eg QuestionComplaintQuestion .并使用不同于它们链接到的实体的具体投诉类型,例如QuestionComplaintQuestion So:所以:

@Entity
@Table(name = "complaints")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Complaint {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date created_on;
}

The user in turn relates to a set of Complaint objects, but is not a Complaint itself (doesn't make sense, does it?)用户又与一组Complaint对象相关,但不是Complaint本身(没有意义,是吗?)

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany(mappedBy = "user_id", orphanRemoval = true, fetch = FetchType.LAZY)
    @ToString.Exclude
    private Set<Complaint> complaints;
}

And the concrete Complaint instances:以及具体的Complaint实例:

@Entity
@Table(name = "question_complaints")
@PrimaryKeyJoinColumn(name = "id")
public class QuestionComplaint extends Complaint {
    @ManyToOne(fetch = FetchType.LAZY)
    private Question question
}

This entity represents the link from Complaint to Question .该实体表示从ComplaintQuestion的链接。 The Question entity, which represents a "Question", no matter if it has complaints attached, may optionally have a relation back to the QuestionComplaint :代表“问题”的Question实体,无论是否附加了投诉,都可以选择与QuestionComplaint建立关系:

@Entity
@Table(name = "questions")
public class Question {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "question")
    private List<QuestionComplaint> complaints;
}

Now usages I expect would be:现在我期望的用法是:

  1. What are the complaints filed by a user?用户提出的投诉是什么? - User.getComplaints() will fetch a UNION ALL of the complaints from all known subtypes - User.getComplaints()将从所有已知子类型中获取一个 UNION ALL 投诉
  2. What are the complaints attachede to a question (answer, etc)?问题(答案等)的抱怨是什么? - question.getComplaints() knows to get records only from the table question_complaints - question.getComplaints()知道只从表question_complaints中获取记录
  3. What complaints has user x filed for question y?用户 x 对问题 y 提出了哪些投诉? - SELECT c FROM QuestionComplaint c WHERE c.user.id =:x AND c.question.id =:y - SELECT c FROM QuestionComplaint c WHERE c.user.id =:x AND c.question.id =:y

Fistly, in java Generic Types can't deteminable in runtime , so JPA can't determine to fetch from which table , so it will throw Exception which you send.首先,在 java Generic Types can't deteminable in runtime ,所以JPA不能确定从哪个table获取,所以它会throw Exception

Secodly your database design is wrong, Complain table will not connect to Question and Answer , Question and Answer need to connect Complain .其次你的数据库设计是错误的, Complain表不会连接到QuestionAnswerQuestionAnswer需要连接Complain Like:像:

Quesiton -|
          v
          ---> Complain ---> User
          ^
Answer   -|

Or you need to add to two fields to Complain table like questionId and answerId .或者您需要将两个字段添加到Complain表中,例如questionIdanswerId

Q u e s i t o n    A n s w e r 
       ^               ^
       |               |
  (questionID)     (answerId)    
       |               |
       +-----------Complain ---> User

One field two foreign table not good design specially for JPA.一域二外表不好专门为JPA设计的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM