Java JPA 多个嵌入字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/331744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA Multiple Embedded fields
提问by Steve Kuo
Is it possible for a JPA entity class to contain two embedded (@Embedded
) fields? An example would be:
JPA 实体类是否可以包含两个嵌入的 ( @Embedded
) 字段?一个例子是:
@Entity
public class Person {
@Embedded
public Address home;
@Embedded
public Address work;
}
public class Address {
public String street;
...
}
In this case a Person
can contain two Address
instances - home and work. I'm using JPA with Hibernate's implementation. When I generate the schema using Hibernate Tools, it only embeds one Address
. What I'd like is two embedded Address
instances, each with its column names distinguished or pre-pended with some prefix (such as home and work). I know of @AttributeOverrides
, but this requires that each attribute be individually overridden. This can get cumbersome if the embedded object (Address
) gets big as each column needs to be individually overridden.
在这种情况下, aPerson
可以包含两个Address
实例 - 家庭和工作。我在 Hibernate 的实现中使用 JPA。当我使用 Hibernate Tools 生成模式时,它只嵌入了一个Address
. 我想要的是两个嵌入式Address
实例,每个实例的列名都可以区分或预先加上一些前缀(例如 home 和 work)。我知道@AttributeOverrides
,但这需要单独覆盖每个属性。如果嵌入的对象 ( Address
) 变大,这会变得很麻烦,因为每一列都需要单独覆盖。
采纳答案by Loki
If you want to have the same embeddable object type twice in the same entity, the column name defaulting will not work: at least one of the columns will have to be explicit. Hibernate goes beyond the EJB3 spec and allows you to enhance the defaulting mechanism through the NamingStrategy. DefaultComponentSafeNamingStrategy is a small improvement over the default EJB3NamingStrategy that allows embedded objects to be defaulted even if used twice in the same entity.
如果您想在同一实体中两次使用相同的可嵌入对象类型,则默认列名将不起作用:至少其中一列必须是显式的。Hibernate 超越了 EJB3 规范,允许您通过 NamingStrategy 增强默认机制。DefaultComponentSafeNamingStrategy 是对默认 EJB3NamingStrategy 的一个小改进,它允许嵌入对象即使在同一实体中使用两次也是默认的。
From Hibernate Annotations Doc: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714
来自 Hibernate 注释文档:http: //docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714
回答by Philihp Busby
The generic JPA way to do it is with @AttributeOverride. This should work in both EclipseLink and Hibernate.
通用的 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;
...
}
}
回答by ruediste
When using Eclipse Link, an alternative to using AttributeOverrides it to use a SessionCustomizer. This solves the issue for all entities in one go:
使用 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);
}
}
}
}
}
}
}
}
回答by Arjan Mels
In case you are using hibernate you can also use a different naming scheme which adds unique prefixes to columns for identical embedded fields. See Automatically Add a Prefix to Column Names for @Embeddable Classes
如果您使用 hibernate,您还可以使用不同的命名方案,为相同的嵌入字段为列添加唯一前缀。请参见自动为@Embeddable 类的列名添加前缀