【问题标题】:JPA Multiple Embedded fieldsJPA 多个嵌入式字段
【发布时间】:2010-09-24 19:25:02
【问题描述】:

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) 变得很大,这可能会变得很麻烦,因为需要单独覆盖每一列。

【问题讨论】:

    标签: java hibernate jpa jakarta-ee


    【解决方案1】:

    通用的 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;
        ...
      }
    }
    

    【讨论】:

    • 注意name="street"指的是属性名,而不是列名。
    • 这是否被认为是“笨拙的”,因为它要求 Person 的开发人员了解有关类 Address 的私密信息(例如包含街道名称的字段的名称)?
    • 哇,所以我必须使用注释重复一遍。 wtf。我也可以自己使用 String homeStreet 手动声明整个嵌入式类;相反,字符串 workStreeet,可能更具确定性。
    • @mmm 在您“wtf”之前,您可能需要花时间了解您所处的不同上下文。为什么要为您可能拥有的每个 foo 创建一个专用的 FooAddress 类引用实体?
    • @Amadán 为我避免冗余。不得不一遍又一遍地重新声明与地址相关的东西的规则。不幸的是,Hibernate 没有提供很好的方法来做到这一点。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      当使用 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);
                              }
                          }
      
                      }
                  }
      
              }
          }
      }
      
      }
      

      【讨论】:

      • +1 将它作为 DescriptorCustomizer 会很好,以便能够控制每个类,但我还没有找到一种方法从 DescriptorCustomizer 中访问嵌入类的 ClassDescriptor主机类。
      • 我现在使用的替代方法是检查 SessionCustomizer 中的 classDescriptor.getJavaClass() 与我希望它影响的类列表。
      【解决方案4】:

      如果您使用的是 hibernate,您还可以使用不同的命名方案,为相同的嵌入字段的列添加唯一的前缀。见Automatically Add a Prefix to Column Names for @Embeddable Classes

      【讨论】:

        猜你喜欢
        • 2012-10-06
        • 1970-01-01
        • 1970-01-01
        • 2019-07-16
        • 1970-01-01
        • 1970-01-01
        • 2019-08-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多