JPA多个embedded式字段
JPA实体类可能包含两个embedded( @Embedded
)字段吗? 一个例子是:
@Entity public class Person { @Embedded public Address home; @Embedded public Address work; } public class Address { public String street; ... }
在这种情况下,一个Person
可以包含两个Address
实例 – 家庭和工作。 我使用Hibernate的实现JPA。 当我使用Hibernate Tools生成模式时,它只embedded一个Address
。 我想要的是两个embedded式Address
实例,每个实例的列名都有区别或者前缀有一些前缀(比如home和work)。 我知道@AttributeOverrides
,但这需要每个属性被单独覆盖。 如果embedded对象( Address
)变大,因为每列都需要被单独覆盖,这会变得很麻烦。
如果您希望在同一个实体中具有相同的可embedded对象types两次,则列名默认将不起作用:至less有一列必须是显式的。 Hibernate超越了EJB3规范,允许您通过NamingStrategy增强默认机制。 DefaultComponentSafeNamingStrategy与默认的EJB3NamingStrategy相比是一个小的改进,即使在同一个实体中使用两次,embedded对象也可以被默认设置。
从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链接时,使用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); } } } } } } } }
如果你正在使用hibernate,你也可以使用不同的命名scheme,为相同的embedded字段的列添加唯一的前缀。 请参阅自动为@Embeddable类的列名称添加前缀