2012-03-27 3 views
6

Ich möchte eine Mail-Entität beibehalten, die über einige Ressourcen verfügt (Inline oder Anhang). Zuerst erzählte ich ihnen als bidirektionaler Beziehung:Unterschiedliches Verhalten mit unidirektionaler oder bidirektionaler Beziehung

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

Und wenn ich sie gerettet:

Mail mail = new Mail("[email protected]", "Hi!", "..."); 
mail.addResource("image", MailResourceType.INLINE, someBytes); 
mail.addResource("documentation.pdf", MailResourceType.ATTACHMENT, someOtherBytes); 
mailRepository.save(mail); 

Drei Einsätze ausgeführt wurden:

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

Dann dachte ich, es nur besser verwenden würde eine OneToMany-Beziehung. Keine Notwendigkeit zu sparen, die E-Mail in jedem MailResource ist:

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

erzeugten Tabellen sind genau die gleichen (MailResource hat einen FK Mail). Das Problem ist das ausgeführte 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 = ?) 

Warum diese zwei Updates? Ich verwende EclipseLink. Ist dieses Verhalten dasselbe, wenn ich einen anderen JPA-Anbieter als Hibernate verwende? Welche Lösung ist besser?

UPDATE: - Wenn ich nicht @JoinColumn Eclipse erstellt drei Tabellen: MAIL, MAILRESOURCE und MAIL_MAILRESOURCE. Ich denke, das ist vollkommen logisch. Aber mit @JoinColumn hat es Informationen genug, um nur zwei Tabellen zu erstellen und meiner Meinung nach nur Inserts, ohne Updates.

Antwort

0

Mapped von definiert Besitzseite der Beziehung so für JPA gibt es einen besseren Weg, um Verbände zu behandeln. Join Column definiert nur die Beziehungsspalte. Da JPA ein komplett reflektionsbasiertes Framework ist, kann ich an die Optimierung von Mapped denken, da es einfach ist, die Seite zu besitzen.

+0

Deuten Sie das mappedBy Attribut OneToMany statt JoinColumn Anmerkung zu benutzen? –

+0

Ja. Ich denke, es wird immer besser funktionieren. –

2

Wenn Sie eine @JoinColumn in OneToMany verwenden, definieren Sie eine "unidirektionale" Eins zu viele, was eine neue Art von Mapping in JPA 2.0 ist, was in JPA 1.0 nicht unterstützt wurde.

Dies ist normalerweise nicht der beste Weg, um OneToMany zu definieren, ein normaler OneToMany wird mit einem mappedBy und einem ManyToOne im Zielobjekt definiert. Andernfalls hat das Zielobjekt keine Kenntnis von diesem Fremdschlüssel und somit auch nicht das separate Update dafür.

Sie können auch eine JoinTable anstelle der JoinColumn verwenden (dies ist die Standardeinstellung für OneToMany), und dann gibt es keinen Fremdschlüssel im Ziel, um den Sie sich sorgen müssen.

Es gibt auch eine vierte Option. Sie könnten die MailResource als Embeddable anstelle von Entity markieren und eine ElementCollection verwenden.

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

+0

Aber ich möchte nur zwei Tabellen (Mail und MailResource) generiert werden. Wenn ich eine ElementCollection von Embeddable verwende, würde ich drei bekommen, oder? – sinuhepop