JPA实体类是否可以包含两个嵌入式(@Embedded
)字段?一个例子是:
@Entity
public class Person {
@Embedded
public Address home;
@Embedded
public Address work;
}
public class Address {
public String street;
...
}
在这种情况下,Person
可以包含两个Address
个实例 - 家庭和工作。我正在使用JPA和Hibernate的实现。当我使用Hibernate Tools生成模式时,它只嵌入一个Address
。我想要的是两个嵌入式Address
实例,每个实例的列名都有区别或预先设置了一些前缀(例如home和work)。我知道@AttributeOverrides
,但这需要单独覆盖每个属性。如果嵌入对象(Address
)变大,因为每个列都需要单独覆盖,这会很麻烦。
答案 0 :(得分:78)
通用的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;
...
}
}
答案 1 :(得分:26)
如果要在同一实体中两次使用相同的可嵌入对象类型,则列名默认将不起作用:至少有一列必须是显式的。 Hibernate超越了EJB3规范,允许您通过NamingStrategy增强默认机制。 DefaultComponentSafeNamingStrategy是对默认EJB3NamingStrategy的一个小改进,它允许默认嵌入对象,即使在同一实体中使用两次也是如此。
来自Hibernate Annotations Doc:http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714
答案 2 :(得分:5)
使用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);
}
}
}
}
}
}
}
}
答案 3 :(得分:1)
如果您正在使用休眠,您还可以使用不同的命名方案,为相同的嵌入字段的列添加唯一的前缀。见Automatically Add a Prefix to Column Names for @Embeddable Classes