web-dev-qa-db-fra.com

JPA Multiple Embedded Fields

Est-il possible pour une classe d'entités JPA de contenir deux (@Embedded) des champs? Un exemple serait:

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

    @Embedded
    public Address work;
}

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

Dans ce cas, un Person peut contenir deux Address instances - home et work. J'utilise JPA avec l'implémentation d'Hibernate. Lorsque je génère le schéma à l'aide des outils Hibernate, il n'incorpore qu'un Address. Ce que je voudrais, ce sont deux instances Address intégrées, chacune avec ses noms de colonne distingués ou précédés d'un préfixe (comme home et work). Je connais @AttributeOverrides, mais cela nécessite que chaque attribut soit remplacé individuellement. Cela peut devenir fastidieux si l'objet incorporé (Address) devient grand car chaque colonne doit être remplacée individuellement.

72
Steve Kuo

Si vous souhaitez avoir le même type d'objet intégrable deux fois dans la même entité, le nom de colonne par défaut ne fonctionnera pas: au moins une des colonnes devra être explicite. Hibernate va au-delà de la spécification EJB3 et vous permet d'améliorer le mécanisme par défaut via NamingStrategy. DefaultComponentSafeNamingStrategy est une petite amélioration par rapport à EJB3NamingStrategy par défaut qui permet aux objets incorporés d'être par défaut même s'ils sont utilisés deux fois dans la même entité.

Extrait du document Hibernate Annotations Doc: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714

26
Loki

La manière générique JPA de le faire est avec @AttributeOverride. Cela devrait fonctionner à la fois dans EclipseLink et Hibernate.

@Entity 
public class Person {
  @AttributeOverrides({
    @AttributeOverride(name="street",column=@Column(name="homeStreet")),
    ...
  })
  @Embedded public Address home;

  @AttributeOverrides({
    @AttributeOverride(name="street",column=@Column(name="workStreet")),
    ...
  })
  @Embedded public Address work;
  }

  @Embeddable public class Address {
    @Basic public String street;
    ...
  }
}
79
Philihp Busby

Lorsque vous utilisez Eclipse Link, une alternative à l'utilisation d'AttributeOverrides pour utiliser un SessionCustomizer. Cela résout le problème pour toutes les entités en une seule fois:

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

                }
            }

        }
    }
}

}
5
ruediste

Dans le cas où vous utilisez hibernate, vous pouvez également utiliser un schéma de dénomination différent qui ajoute des préfixes uniques aux colonnes pour des champs intégrés identiques. Voir Ajouter automatiquement un préfixe aux noms de colonne pour les classes @Embeddable

1
Arjan Mels