2012-11-28 11 views
8

Grundlegende Frage: Warum werden @Embedded-Objekte nicht immer instanziiert?@Embedded-Objekt wird nicht automatisch instanziiert, wenn es keine grundlegenden Datentypfelder hat

Die interessante Beobachtung ist, dass Ebean @Embedded-Objekte nicht instanziiert, wenn diese keine grundlegenden Datentypen (int, boolean ...) enthalten oder vorher nicht berührt wurden. Beispiel:

@Entity 
public class Embedder { 
    // getNotAutoInstantiated() will return null if this field was not touched before 
    @Embedded 
    private NotAutoInstantiated notAutoInstantiated = new NotAutoInstantiated(); 
    // getAutoInstantiated() will always return an instance! 
    @Embedded 
    private AutoInstantiated autoInstantiated = new AutoInstantiated(); 
} 

@Embeddable 
public class AutoInstantiated { 
    // theKey is why this embedded object is always instantiated 
    private int theKey; 
    private String field1;  
} 

@Embeddable 
public class NotAutoInstantiated { 
    private String field2;  
} 
+0

Möglicherweise tritt ein Problem mit Feldnamen-Kollisionen zwischen mehreren eingebetteten Objekten auf. Normalerweise ordnet der JPA-Anbieter die Felder für eingebettete Objekte den Spalten in der übergeordneten Tabelle zu. Wenn die eingebetteten Feldnamen lange ausgeführt werden, können Sie abgeschnittene Feldnamen in der Datenbank und damit Kollisionen in den Spaltennamen erhalten. – Zagrev

+0

Das Beispiel kann täuschen. Die Namen sind in meinem Code viel kürzer und sie beginnen nicht mit dem gleichen Präfix. Aber auch im Beispiel beginnen die Felder mit "not" und "auto", also wäre die Kürzung kein großes Problem. – allprog

+0

Eigentlich habe ich über "field" und "field" nachgedacht. – Zagrev

Antwort

3

Ich glaube nicht, dass die JPA-Spezifikation beschreibt deutlich, was passieren soll, wenn ein @Embedded Eigenschaft des Objekts all null ist, aber zumindest einige Implementierungen behandeln ein Objekt mit null Eigenschaften als ein Null-Objekt, das ist was du siehst.

Dies scheint eine sinnvolle Implementierung. Sicherlich war es in meinem Code nützlich (mit Hibernate), wenn ich ein @Embedded Objekt auf null setze, möchte ich, dass es null bleibt, wenn ich eine persistente Version lade.

In Ihrem Beispiel kann die Klasse AutoInstantiated niemals als null betrachtet werden, da die primitive Eigenschaft theKey niemals null sein kann.

+0

Leider ist die Situation schlimmer. Ebean scheint mit diesem Verhalten nicht übereinzustimmen. Wir haben ein ziemlich komplexes Datenmodell, in dem AutoInstantiated-ähnliche @Embedded-Felder an den meisten Stellen automatisch instanziiert werden. Aber es gibt einen Ort, wo das nicht passiert.Wir waren nicht in der Lage, die Besonderheit dieses einen zu finden. Der Ansatz "leaving it null" ist nicht der beste für mich, da es eine weitere Nullprüfung erfordert. Dies ist die schlechteste Vorgehensweise in Java. Es könnte in solchen Fällen leicht vermieden werden ... – allprog

3

Vielleicht möchten Sie überprüfen:

https://hibernate.atlassian.net/browse/HHH-7610

Insbesondere seit 5.1:

static final String CREATE_EMPTY_COMPOSITES_ENABLED 

Enable instantiation of composite/embedded objects when all of its 
attribute values are null. The default (and historical) behavior is that a null reference 
will be used to represent the composite when all of its attributes are null 
@since 5.1 
@see Constant Field Values 

Stellen Sie die hibernate.create_empty_composites.enabled Eigenschaft auf true und voilà!

+0

Danke, das ist gut zu wissen. Die Frage bezieht sich jedoch auf EBean. Hibernate ist wahrscheinlich in vielen Aspekten überlegen, aber Ebean passt besser zu kleinen Projekten. – allprog

1

Ich habe gerade das gleiche Problem mit Hibernate. Die ursprüngliche Frage nach dem "Warum" wird beantwortet.

Aber über eine Lösung zu sprechen, verwende ich nur eine @PostLoad Methode, so innerhalb der Klasse Embedder so etwas wie:

@PostLoad 
private void initData() { 
    if(notAutoInstantiated == null) { 
    notAutoInstantiated = new NotAutoInstantiated(); 
    } 
} 

Update:

Achtung! Der obere Code funktioniert, hat aber einen unerwarteten Nebeneffekt! Sobald Sie Ihr Objekt mit einem Null-Zeiger aus der Datenbank geladen haben, wird es aufgrund dieses Post-Load-Codes als fehlerhaft markiert! In meinem Fall führt diese Nebenwirkungen zu einem SQL-Update-Befehl von einem Thread, der nur die Daten und Stunden der Suche dieses Fehlers laden sollte!