JPA 다중 임베디드 필드


84

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각 열을 개별적으로 재정의해야 하므로 포함 된 개체 ( )가 커지면 번거로울 수 있습니다 .

답변:


28

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

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


89

이를 수행하는 일반적인 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;
    ...
  }
}

9
name="street"열 이름이 아니라 속성의 이름 을 나타냅니다.
Bart Swennenhuis

Person 개발자가 Address 클래스에 대한 친밀한 정보 (예 : 거리 이름이 포함 된 필드의 이름)를 알아야하므로 "투박한"것으로 간주됩니까?
mbmast

와우, 주석을 사용하여 모두 반복해야합니다. wtf. String homeStreet를 사용하여 직접 전체 임베디드 클래스를 직접 선언 할 수 있습니다. 대신에 workStreeet 문자열이 더 결정적 일 것입니다.
mmm

6

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

                }
            }

        }
    }
}

}

+1 클래스별로이를 제어 할 수 있도록 DescriptorCustomizer로 사용하는 것이 좋지만 호스트 클래스의 DescriptorCustomizer 내에서 포함 된 클래스의 ClassDescriptor에 액세스하는 방법을 찾지 못했습니다.
oulenz

1
내가 지금 사용하고있는 대안은 내가 적용 할 classDescriptor.getJavaClass()클래스 목록에 대해 SessionCustomizer 를 확인 하는 것입니다.
oulenz

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.