web-dev-qa-db-ja.com

JPA複数埋め込みフィールド

JPAエンティティクラスに2つの埋め込み(@Embedded) 田畑?例は次のとおりです。

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

    @Embedded
    public Address work;
}

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

この場合、Personには2つのAddressインスタンス(自宅と職場)を含めることができます。 Hibernateの実装でJPAを使用しています。 Hibernate Toolsを使用してスキーマを生成すると、1つのAddressのみが埋め込まれます。私が望んでいるのは、2つの埋め込みAddressインスタンスで、それぞれの列名が区別されているか、いくつかのプレフィックス(homeやworkなど)が前に付いています。 @AttributeOverrides、ただしこれには各属性を個別にオーバーライドする必要があります。各列を個別にオーバーライドする必要があるため、埋め込みオブジェクト(Address)が大きくなると、これは面倒になります。

72
Steve Kuo

同じエンティティに同じ埋め込みオブジェクトタイプを2回使用する場合、列名のデフォルト設定は機能しません。少なくとも1つの列を明示的に指定する必要があります。 HibernateはEJB3仕様を超えており、NamingStrategyを介してデフォルトのメカニズムを強化できます。 DefaultComponentSafeNamingStrategyは、デフォルトのEJB3NamingStrategyをわずかに改善したもので、同じエンティティで2回使用した場合でも埋め込みオブジェクトをデフォルトに設定できます。

Hibernate Annotations Docから: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714

26
Loki

一般的なJPAの方法は@AttributeOverrideを使用することです。これは、EclipseLinkと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;
    ...
  }
}
79
Philihp Busby

Eclipse Linkを使用する場合、AttributeOverrideを使用する代わりにSessionCustomizerを使用します。これにより、すべてのエンティティの問題が一度に解決します。

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

Hibernateを使用している場合は、同じ埋め込みフィールドの列に一意のプレフィックスを追加する別の命名スキームを使用することもできます。 @ Embeddableクラスの列名に自動的にプレフィックスを追加する を参照してください

1
Arjan Mels