java - 使用单向或双向关系的不同行为

标签 java hibernate jpa orm eclipselink

我想保留一个具有某些资源(内联或附件)的邮件实体。首先,我将它们关联为双向关系:

@Entity
public class Mail extends BaseEntity {

    @OneToMany(mappedBy = "mail", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<MailResource> resource;

    private String receiver;
    private String subject;
    private String body;

    @Temporal(TemporalType.TIMESTAMP)
    private Date queued;

    @Temporal(TemporalType.TIMESTAMP)
    private Date sent;

    public Mail(String receiver, String subject, String body) {
        this.receiver = receiver;
        this.subject = subject;
        this.body = body;
        this.queued = new Date();
        this.resource = new ArrayList<>();
    }

    public void addResource(String name, MailResourceType type, byte[] content) {
        resource.add(new MailResource(this, name, type, content));
    }

}

@Entity
public class MailResource extends BaseEntity {

    @ManyToOne(optional = false)
    private Mail mail;

    private String name;
    private MailResourceType type;
    private byte[] content;
}

当我保存它们时:

Mail mail = new Mail("asdasd@asd.com", "Hi!", "...");
mail.addResource("image", MailResourceType.INLINE, someBytes);
mail.addResource("documentation.pdf", MailResourceType.ATTACHMENT, someOtherBytes);
mailRepository.save(mail);

执行了三个插入:

INSERT INTO MAIL (ID, BODY, QUEUED, RECEIVER, SENT, SUBJECT) VALUES (?, ?, ?, ?, ?, ?)
INSERT INTO MAILRESOURCE (ID, CONTENT, NAME, TYPE, MAIL_ID) VALUES (?, ?, ?, ?, ?)
INSERT INTO MAILRESOURCE (ID, CONTENT, NAME, TYPE, MAIL_ID) VALUES (?, ?, ?, ?, ?)

然后我认为只使用 OneToMany 关系会更好。无需保存每个邮件资源中的邮件:

@Entity
public class Mail extends BaseEntity {

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "mail_id")
    private List<MailResource> resource;

    ...

    public void addResource(String name, MailResourceType type, byte[] content) {
        resource.add(new MailResource(name, type, content));
    }

}

@Entity
public class MailResource extends BaseEntity {
    private String name;
    private MailResourceType type;
    private byte[] content;
}

生成的表完全一样(MailResource 有一个 FK to Mail)。问题是执行的SQL:

INSERT INTO MAIL (ID, BODY, QUEUED, RECEIVER, SENT, SUBJECT) VALUES (?, ?, ?, ?, ?, ?)
INSERT INTO MAILRESOURCE (ID, CONTENT, NAME, TYPE) VALUES (?, ?, ?, ?)
INSERT INTO MAILRESOURCE (ID, CONTENT, NAME, TYPE) VALUES (?, ?, ?, ?)
UPDATE MAILRESOURCE SET mail_id = ? WHERE (ID = ?)
UPDATE MAILRESOURCE SET mail_id = ? WHERE (ID = ?)

为什么这两个更新?我正在使用 EclipseLink,使用另一个 JPA 提供程序作为 Hibernate 时,这种行为是否相同?哪种方案更好?

更新: - 如果我不使用@JoinColumn,EclipseLink 会创建三个表:MAIL、MAILRESOURCE 和 MAIL_MAILRESOURCE。我认为这是完全合乎逻辑的。但是对于@JoinColumn,它拥有的信息足以只创建两个表,而且在我看来,它只做插入,不做更新。

最佳答案

当您在 OneToMany 中使用 @JoinColumn 时,您定义的是“单向”一对多,这是 JPA 2.0 中添加的一种新型映射,JPA 1.0 不支持它。

这通常不是定义 OneToMany 的最佳方式,普通的 OneToMany 是使用 mappedBy 定义的,并在目标对象中包含 ManyToOne。否则目标对象不知道这个外键,因此不知道它的单独更新。

您还可以使用 JoinTable 而不是 JoinColumn(这是 OneToMany 的默认设置),这样目标中就没有外键需要担心了。

还有第四种选择。您可以将 MailResource 标记为 Embeddable 而不是 Entity 并使用 ElementCollection。

看, http://en.wikibooks.org/wiki/Java_Persistence/OneToMany

关于java - 使用单向或双向关系的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9899149/

相关文章:

java - 无法为指定的 SELECT 语句定义 SENSITIVE 游标 "SQL_CURSH200C1"。 SQLCODE=-243,SQLSTATE=36001,DRIVER=4.13.127

java - 使用 MYSQL 表结构创建 JPA 映射时遇到问题

java - 解决 PermGen 问题的各种选择

java - 如何获取在使用 JOptionPane.showOptionDialog 时单击了哪个选项?为什么会出现不兼容类型错误

java - Hibernate:通过单个连接表引用多个表

java - Spring in Action 第 6 章,项目未启动

java - 如何在 JPA 实体中创建非持久字段?

java - 使用 TABLE_PER_CLASS 继承策略在 JPA 模式上存储子实体时写入父实体的策略

java - 如何使用eclipse在Java中的JFrame中的特定位置添加图像?

java - 如何使用 STAX 将文件写入 xml?