[java] JPA 다중 임베디드 필드

JPA 엔티티 클래스에 두 개의 임베디드 ( @Embedded) 필드 가 포함될 수 있습니까? 예는 다음과 같습니다.

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

    @Embedded
    public Address work;
}

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

이 경우 a Person에는 Address집과 직장의 두 인스턴스 가 포함될 수 있습니다 . Hibernate의 구현과 함께 JPA를 사용하고 있습니다. Hibernate Tools를 사용하여 스키마를 생성 할 때 Address. 내가 원하는 것은 Address각각 열 이름이 구별되거나 접두사 (예 : 집 및 직장) 가 추가 된 두 개의 임베디드 인스턴스입니다. 알고 @AttributeOverrides있지만이를 위해서는 각 속성을 개별적으로 재정의해야합니다. Address각 열을 개별적으로 재정의해야 하므로 포함 된 개체 ( )가 커지면 번거로울 수 있습니다 .



답변

동일한 엔터티에서 동일한 포함 가능한 개체 유형을 두 번 사용하려는 경우 열 이름 기본값이 작동하지 않습니다. 열 중 하나 이상이 명시 적이어야합니다. Hibernate는 EJB3 사양을 넘어서 NamingStrategy를 통해 디폴트 메커니즘을 향상시킬 수 있습니다. DefaultComponentSafeNamingStrategy는 기본 EJB3NamingStrategy에 비해 약간 개선 된 것으로, 동일한 엔터티에서 두 번 사용되는 경우에도 포함 된 개체를 기본값으로 설정할 수 있습니다.

Hibernate Annotations 문서에서 : http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714


답변

이를 수행하는 일반적인 JPA 방법은 @AttributeOverride를 사용하는 것입니다. 이것은 EclipseLink와 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;
    ...
  }
}


답변

Eclipse Link를 사용할 때 AttributeOverrides를 사용하는 대신 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);
                        }
                    }

                }
            }

        }
    }
}

}


답변

최대 절전 모드를 사용하는 경우 동일한 포함 된 필드의 열에 고유 한 접두사를 추가하는 다른 명명 체계를 사용할 수도 있습니다. @Embeddable 클래스의 열 이름에 자동으로 접두사 추가를 참조하십시오.


답변