JPA:两个实体之间的多对多关系如何处理?

8

我有两个实体类'用户'和'文档'。每个用户都有一个收件箱和发件箱,实际上是两个列表,每个文档可能会驻留在多个用户的收件箱和发件箱中。以下是我的类:

@Entity
public class User {

    @Id
    private Long id;

    @ManyToMany(mappedBy = "userinbox", cascade=CascadeType.ALL)
    private List<Document> inbox = new ArrayList<Document>();
    @ManyToMany(mappedBy = "useroutbox", cascade=CascadeType.ALL)
    private List<Document> outbox = new ArrayList<Document>();

}

@Entity
public class Document {

    @Id
    private Long id;

    @ManyToMany(cascade=CascadeType.ALL)
    private List<User> userinbox  = new ArrayList<User>();
    @ManyToMany(cascade=CascadeType.ALL)
    private List<User> useroutbox  = new ArrayList<User>();

}

当我运行程序并尝试将文档分配给用户的收件箱(反之亦然)时,出现以下错误:
Error Code: 1364

Call: INSERT INTO DOCUMENT_USER (userinbox_ID, inbox_ID) VALUES (?, ?)
    bind => [2 parameters bound]

Internal Exception: java.sql.SQLException: Field 'useroutbox_ID' doesn't have a default value

Query: DataModifyQuery(name="userinbox" sql="INSERT INTO DOCUMENT_USER (userinbox_ID, inbox_ID) VALUES (?, ?)")

生成的关联表看起来像这样:
DOCUMENT_USER
useroutbox_ID | outbox_ID |userinbox_ID | inbox_ID

我该如何为这样的多对多关系分配默认值?是创建两个关联表——一个用于收件箱关系,另一个用于发件箱关系更好吗?我该如何实现?还有其他解决办法吗?
非常感谢您的帮助!

尝试将@ManyToMany(cascade = CascadeType.ALL)放在其getter方法而不是字段上。 - user982733
@tech_learner 在字段中放置注释是可以的,这不是问题所在。 - Alonso Dominguez
1个回答

18

我认为更好的选择是拥有两个独立的表,每个表与一种关系相对应。因为实际上你有两个不同实体之间的关系,而不是一种包含四个不同实体的关系。

所以,在Document端的每个属性上添加一个@JoinTable注释,因为在User端这些关系被映射到一个属性。类似以下内容:

@Entity
public class Document {

    @Id
    private Long id;

    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "document_inbox", joinColumns = @JoinColumn(name = "userinbox_id"),
               inverseJoinColumns = @JoinColumn(name = "inbox_id"))
    private List<User> userinbox  = new ArrayList<User>();
    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "document_outbox", joinColumns = @JoinColumn(name = "useroutbox_id"),
               inverseJoinColumns = @JoinColumn(name = "outbox_id"))
    private List<User> useroutbox  = new ArrayList<User>();

}

将另一个实体保持现状。希望这可以帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接