2008-12-01 75 views
68

JPA實體類可能包含兩個嵌入的(@Embedded)字段嗎?一個例子是:JPA Multiple Embedded fields

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

    @Embedded 
    public Address work; 
} 

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

在這種情況下,Person可以包含兩個Address實例 - 家庭和工作。我使用Hibernate的實現JPA。當我使用Hibernate Tools生成模式時,它只嵌入一個Address。我想要的是兩個嵌入的Address實例,每個實例的列名都被區分或預先添加了一些前綴(如家庭和工作)。我知道@AttributeOverrides,但這需要每個屬性被單獨覆蓋。如果嵌入對象(Address)變大,因爲每列都需要單獨覆蓋,這會變得很麻煩。

回答

25

如果您希望在同一個實體中具有相同的可嵌入對象類型兩次,則列名默認將不起作用:至少有一列必須是顯式的。 Hibernate超越了EJB3規範,允許您通過NamingStrategy增強默認機制。 DefaultComponentSafeNamingStrategy與默認的EJB3NamingStrategy相比是一個小改進,它允許即使在同一個實體中使用兩次嵌入對象也是默認的。

從Hibernate註解文件:http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714

74

通用JPA的方式來做到這一點是與@AttributeOverride。這應該可以在EclipseLink和Hibernate中使用。

@Entity 
public class Person { 
    @AttributeOverrides({ 
    @AttributeOverride(name="street",[email protected](name="homeStreet")), 
    ... 
    }) 
    @Embedded public Address home; 

    @AttributeOverrides({ 
    @AttributeOverride(name="street",[email protected](name="workStreet")), 
    ... 
    }) 
    @Embedded public Address work; 
    } 

    @Embeddable public class Address { 
    @Basic public String street; 
    ... 
    } 
} 
+5

請注意,`name =「street」`指的是屬性的名稱,而不是列名。 – 2015-08-17 14:41:44

3

使用Eclipse鏈接時,使用AttributeO的替代方法將其用於使用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); 
         } 
        } 

       } 
      } 

     } 
    } 
} 

} 
+0

+1將DescriptorCustomizer作爲DescriptorCustomizer的好處,可以控制每個類,但是我還沒有找到一種方法從宿主類的DescriptorCustomizer中訪問嵌入類的ClassDescriptor。 – oulenz 2016-09-19 13:47:00