Tôi muốn tồn tại một thực thể thư có một số tài nguyên (nội tuyến hoặc tệp đính kèm). Trước tiên tôi liên quan đến chúng như là một mối quan hệ hai chiều:Hành vi khác nhau sử dụng quan hệ một chiều hoặc hai chiều
@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;
}
Và khi tôi lưu chúng:
Mail mail = new Mail("[email protected]", "Hi!", "...");
mail.addResource("image", MailResourceType.INLINE, someBytes);
mail.addResource("documentation.pdf", MailResourceType.ATTACHMENT, someOtherBytes);
mailRepository.save(mail);
Ba chèn được thực hiện:
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 (?, ?, ?, ?, ?)
Sau đó, tôi nghĩ rằng nó sẽ được sử dụng tốt hơn chỉ một mối quan hệ OneToMany. Không cần phải lưu Thư nào trong mỗi MailResource:
@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;
}
Bảng đã tạo giống hệt nhau (MailResource có FK thành Thư). Vấn đề là SQL được thực thi:
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 = ?)
Tại sao hai cập nhật này lại xảy ra? Tôi đang sử dụng EclipseLink, hành vi này sẽ giống như vậy khi sử dụng một nhà cung cấp JPA khác như Hibernate? Giải pháp nào tốt hơn?
CẬP NHẬT: - Nếu tôi không sử dụng @JoinColumn EclipseLink sẽ tạo ba bảng: MAIL, MAILRESOURCE và MAIL_MAILRESOURCE. Tôi nghĩ điều này hoàn toàn logic. Nhưng với @JoinColumn nó có đủ thông tin để tạo chỉ có hai bảng và, theo ý kiến của tôi, chỉ chèn, không có cập nhật.
Bạn có gợi ý để sử dụng thuộc tính mappedBy của OneToMany thay vì JoinColumn chú thích? –
Có. Tôi nghĩ rằng nó sẽ luôn luôn làm việc tốt hơn theo cách đó. –