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 클래스의 열 이름에 자동으로 접두사 추가를 참조하십시오.