2008-12-01 21 views
68

¿Es posible que una clase de entidad JPA contenga dos campos incrustados (@Embedded)? Un ejemplo sería:JPA Múltiples campos incrustados

@Entity 
public class Person { 
    @Embedded 
    public Address home; 

    @Embedded 
    public Address work; 
} 

public class Address { 
    public String street; 
    ... 
} 

En este caso, un Person puede contener dos casos Address - hogar y el trabajo. Estoy usando JPA con la implementación de Hibernate. Cuando genero el esquema usando Hibernate Tools, solo incrusta uno Address. Lo que me gustaría es dos instancias Address incrustadas, cada una con sus nombres de columna distinguidos o preincorporados con algún prefijo (como el hogar y el trabajo). Sé de @AttributeOverrides, pero esto requiere que cada atributo se anule de forma individual. Esto puede volverse engorroso si el objeto incrustado (Address) se agranda, ya que cada columna debe sobrescribirse individualmente.

Respuesta

25

Si desea tener el mismo objeto incrustado, escriba dos veces en la misma entidad, el nombre predeterminado de la columna no funcionará: al menos una de las columnas tendrá que ser explícita. Hibernate va más allá de la especificación EJB3 y le permite mejorar el mecanismo predeterminado a través de NamingStrategy. DefaultComponentSafeNamingStrategy es una pequeña mejora sobre la EJB3NamingStrategy predeterminada que permite que los objetos incrustados sean predeterminados incluso si se usan dos veces en la misma entidad.

De Hibernate Anotaciones Doc: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714

74

La forma genérica de la APP de hacerlo es con @AttributeOverride. Esto debería funcionar tanto en EclipseLink como en Hibernate.

@Entity 
public class Person { 
    @AttributeOverrides({ 
    @AttributeOverride(name="street",[email protected](name="homeStreet")), 
    ... 
    }) 
    @Embedded public Address home; 

    @AttributeOverrides({ 
    @AttributeOverride(name="street",[email protected](name="workStreet")), 
    ... 
    }) 
    @Embedded public Address work; 
    } 

    @Embeddable public class Address { 
    @Basic public String street; 
    ... 
    } 
} 
+5

Tenga en cuenta que 'name =" street "' hace referencia al nombre de la propiedad, no al nombre de la columna. –

3

Al utilizar Eclipse Link, una alternativa al uso AttributeOverrides que utilice un SessionCustomizer. Esto resuelve el problema para todas las entidades de una sola vez:

public class EmbeddedFieldNamesSessionCustomizer implements SessionCustomizer { 

@SuppressWarnings("rawtypes") 
@Override 
public void customize(Session session) throws Exception { 
    Map<Class, ClassDescriptor> descriptors = session.getDescriptors(); 
    for (ClassDescriptor classDescriptor : descriptors.values()) { 
     for (DatabaseMapping databaseMapping : classDescriptor.getMappings()) { 
      if (databaseMapping.isAggregateObjectMapping()) { 
       AggregateObjectMapping m = (AggregateObjectMapping) databaseMapping; 
       Map<String, DatabaseField> mapping = m.getAggregateToSourceFields(); 

       ClassDescriptor refDesc = descriptors.get(m.getReferenceClass()); 
       for (DatabaseMapping refMapping : refDesc.getMappings()) { 
        if (refMapping.isDirectToFieldMapping()) { 
         DirectToFieldMapping refDirectMapping = (DirectToFieldMapping) refMapping; 
         String refFieldName = refDirectMapping.getField().getName(); 
         if (!mapping.containsKey(refFieldName)) { 
          DatabaseField mappedField = refDirectMapping.getField().clone(); 
          mappedField.setName(m.getAttributeName() + "_" + mappedField.getName()); 
          mapping.put(refFieldName, mappedField); 
         } 
        } 

       } 
      } 

     } 
    } 
} 

} 
+0

+1 Sería bueno tener esto como DescriptorCustomizer, para poder controlar esto por clase, pero no he encontrado una manera de acceder al ClassDescriptor de la clase incrustada desde DescriptorCustomizer de la clase de host. – oulenz

+0

La alternativa que estoy usando ahora es comprobar 'classDescriptor.getJavaClass()' en el SessionCustomizer contra una lista de clases que quiero que afecte. – oulenz

Cuestiones relacionadas