84

JPA 实体类是否可以包含两个嵌入的 ( @Embedded) 字段?一个例子是:

@Entity
public class Person {
    @Embedded
    public Address home;

    @Embedded
    public Address work;
}

public class Address {
    public String street;
    ...
}

在这种情况下, aPerson可以包含两个Address实例 - home 和 work。我将 JPA 与 Hibernate 的实现一起使用。当我使用 Hibernate Tools 生成模式时,它只嵌入了一个Address. 我想要的是两个嵌入式Address实例,每个实例的列名都有区别或前缀有一些前缀(例如 home 和 work)。我知道@AttributeOverrides,但这需要单独覆盖每个属性。如果嵌入对象 ( Address) 变得很大,因为需要单独覆盖每一列,这会变得很麻烦。

4

4 回答 4

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;
    ...
  }
}
于 2012-02-12T05:18:25.463 回答
29

如果您想在同一个实体中拥有相同的可嵌入对象类型两次,默认的列名将不起作用:至少其中一个列必须是显式的。Hibernate 超越了 EJB3 规范,允许您通过 NamingStrategy 增强默认机制。DefaultComponentSafeNamingStrategy 是对默认 EJB3NamingStrategy 的一个小改进,即使在同一实体中使用两次,它也允许默认嵌入对象。

来自休眠注释文档:http ://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714

于 2008-12-01T19:09:07.520 回答
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);
                        }
                    }

                }
            }

        }
    }
}

}
于 2016-03-16T18:14:39.630 回答
1

如果您使用的是 hibernate,您还可以使用不同的命名方案,为相同的嵌入字段的列添加唯一的前缀。请参阅自动为 @Embeddable 类的列名添加前缀

于 2017-03-25T15:38:09.073 回答