Different behavior using unidirectional or bi-directional relation

I want to save a mail object that has some resources (inline or attachments). At first I linked them as a bi-directional relation:

@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; } 

And when I saved them:

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

Three inserts were made:

 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 (?, ?, ?, ?, ?) 

Then I thought it was better to use only the OneToMany relationship. No need to save which mail is in each 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; } 

The generated tables are exactly the same (MailResource has an FK for Mail). The problem is the executed 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 = ?) 

Why are these two updates? I use EclipseLink, will this behavior be the same using another JPA provider like Hibernate? Which solution is better?

UPDATE: - If I do not use @JoinColumn, EclipseLink creates three tables: MAIL, MAILRESOURCE and MAIL_MAILRESOURCE. I think this is completely logical. But with @JoinColumn he has enough information to create only two tables and, in my opinion, only do inserts without updates.

+6
source share
2 answers

When you use @JoinColumn in OneToMany, you define a โ€œone-wayโ€ one for many, which is a new type of mapping added in JPA 2.0, it was not supported in JPA 1.0.

This is usually not the best way to determine OneToMany, the normal OneToMany is defined using mappedBy and has ManyToOne in the target. Otherwise, the target does not know this foreign key and, therefore, a separate update for it.

You can also use JoinTable instead of JoinColumn (this is the default value for OneToMany) and then there will be no foreign key in it.

There is also a fourth option. You can mark MailResource as embeddable instead of Entity and use ElementCollection.

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

+2
source

It is displayed by defining its own side of the relationship, so for JPA it provides the best way to handle associations. The Join column only defines the relationship column. Since the JPA is a completely reflection-based framework, I could think of an optimization made for Mapped, as it is easy to find this side this way.

0
source

Source: https://habr.com/ru/post/911820/


All Articles