Quiero persistir una entidad de correo que tiene algunos recursos (en línea o adjuntos). Primero les relacionados como una relación bidireccional:Comportamiento diferente usando la relación unidireccional o bidireccional
@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;
}
Y cuando los salvó fueron ejecutados
Mail mail = new Mail("[email protected]", "Hi!", "...");
mail.addResource("image", MailResourceType.INLINE, someBytes);
mail.addResource("documentation.pdf", MailResourceType.ATTACHMENT, someOtherBytes);
mailRepository.save(mail);
tres inserciones:
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 (?, ?, ?, ?, ?)
luego pensé que sería mejor utilizando sólo una relación OneToMany. No hay necesidad de guardar el cual Mail es en todos los 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;
}
tablas generadas son exactamente los mismos (MailResource tiene una FK a Correo). El problema es el SQL ejecutado:
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 = ?)
¿Por qué estas dos actualizaciones? Estoy usando EclipseLink, ¿este comportamiento será el mismo usando otro proveedor de JPA como Hibernate? ¿Qué solución es mejor?
ACTUALIZACIÓN: - Si yo no uso @JoinColumn EclipseLink crea tres tablas: CORREO, MAILRESOURCE y MAIL_MAILRESOURCE. Creo que esto es perfectamente lógico. Pero con @JoinColumn tiene suficiente información para crear solo dos tablas y, en mi opinión, solo inserta, sin actualizaciones.
¿Estás sugiriendo utilizar el atributo de mappedBy OneToMany en lugar de JoinColumn anotación? –
Sí. Creo que siempre funcionará mejor de esa manera. –