2012-11-28 16 views
8

Domanda fondamentale: perché gli oggetti @Embedded non vengono sempre istanziati?@ L'oggetto incorporato non viene istanziato automaticamente se non contiene campi di dati di base

L'osservazione interessante è che Ebean non istanzia gli oggetti @Embedded se questi non contengono tipi di dati di base (int, booleano ...) o non sono stati toccati prima. Esempio:

@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

Potrebbe essersi verificato un problema con collisioni di nomi di campi tra più oggetti incorporati. Normalmente, il provider JPA associa i campi degli oggetti incorporati alle colonne nella tabella padre. Se i nomi dei campi incorporati vengono eseguiti a lungo, si può finire con nomi di campi troncati nel database e quindi collisioni nei nomi delle colonne. – Zagrev

+0

L'esempio potrebbe essere ingannevole. I nomi sono molto più brevi nel mio codice e non iniziano con lo stesso prefisso. Ma anche nell'esempio i campi iniziano con "not" e "auto", quindi il troncamento non sarebbe un grosso problema. – allprog

+0

In realtà, stavo pensando a "campo" e "campo". – Zagrev

risposta

3

Non credo che la specifica JPA descrive chiaramente quello che dovrebbe accadere quando le proprietà di un oggetto @Embedded sono tutti nulli, ma almeno alcune implementazioni trattare un oggetto con proprietà nulli come un oggetto null, che è quello che stai vedendo.

Questa sembra un'implementazione ragionevole. Certamente è stato utile nel mio codice (usando Hibernate), dove se ho impostato un oggetto @Embedded su null, voglio che rimanga nullo quando carico una versione persistente.

Nel tuo esempio, la classe AutoInstantiated non può mai essere considerata nulla, poiché la proprietà primitiva theKey non può mai essere nullo.

+0

Sfortunatamente, la situazione è peggiore. Ebean sembra non essere coerente con questo comportamento. Disponiamo di un modello di dati piuttosto complesso in cui i campi @ Smart incorporati come AutoInstantiated sono realmente istanziati automaticamente nella maggior parte dei luoghi. Ma c'è un posto dove questo non accade.Non siamo riusciti a trovare la particolarità di quello. L'approccio "lasciarlo nulla" non è il migliore per me in quanto richiede un altro controllo nullo. Questa è la peggiore pratica in Java. Potrebbe essere facilmente evitato in questi casi ... – allprog

3

Si potrebbe voler controllare:

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

In particolare, dal 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 

Impostare la proprietà hibernate.create_empty_composites.enabled true e voilà!

+0

Grazie, questo è bello sapere. Tuttavia, la domanda è correlata a EBean. L'ibernazione è probabilmente superiore in molti aspetti, ma Ebean si adatta meglio ai piccoli progetti. – allprog

1

Ho appena raggiunto lo stesso problema con Hibernate. La domanda originale, sul "perché" è stata data una risposta.

Ma per parlare di una soluzione, mi basta usare un metodo @PostLoad, quindi nella classe Embedder qualcosa di simile:

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

Aggiornamento:

Attenzione! Il codice superiore funziona, ma ha un effetto collaterale inaspettato! Non appena carichi l'oggetto con un puntatore nullo dal database, viene contrassegnato come sporco, a causa di questo codice di caricamento post! Nel mio caso, questi effetti collaterali portano a un comando di aggiornamento SQL da un thread, che dovrebbe caricare solo i dati e le ore di ricerca di questo bug!