2014-03-19 28 views
1

我有一个可嵌入地址的Person实体,并且它们之间存在一对多关系(一个人可以有多个地址)。目前的映射是这样的:休眠嵌入式列表映射与标识符

@Embeddable 
public class Address { 
    // ... attributes 
} 

@Entity 
public class Person { 
    @ElementCollection(fetch = FetchType.EAGER) 
    @JoinTable(name = "Person_addresses", joinColumns = @JoinColumn(name = "personid") 
    ) 
    /* 
    Attribute ovverrides with annotations 
    */ 
    private java.util.Set<Address> addresses = new java.util.HashSet<Address>();  
} 

使用这个注解意味着,在数据库中我有一个包含了所有的地址属性和PERSONID一个Person_addresses表。但是这也意味着如果我有一个拥有地址列表的人并且我更新了地址列表,那么Hibernate会删除所有相关记录并再次插入它们(修改过的记录)。

据我所知,有一种方法可以在每个记录的表中有一个主键 - 在这种情况下,hibernate可以决定需要更新列表中的哪个项目。所以我的问题是,如何在连接表中映射带有标识符的可嵌入列表? (我希望这是可以理解的,我想:))。

回答

2

http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection#Primary_keys_in_CollectionTable

JPA 2.0规范不提供方式中 可嵌入到定义的ID。但是,要删除或更新ElementCollection映射的元素,通常需要一些唯一的密钥。 否则,在每次更新时,JPA提供程序需要删除 中的所有内容,然后将该值插回 。因此,JPA提供商很可能会认为Embeddable中所有字段的 组合都是唯一的, 与外键(JoinColumn(s))的组合。然而,这可能会导致效率低下,或者如果Embeddable很大或 错综复杂,就不可行。某些JPA提供商可能允许在可嵌入的 中指定Id,以解决此问题。请注意,在这种情况下,Id仅需要 对于集合而言是唯一的,而不是表格,因为外键包含 。有些也可能允许CollectionTable 上的唯一选项用于此目的。否则,如果您的Embeddable很复杂,您可以考虑将其设为实体并使用OneToMany。

因此,它不能这样做。

2

正如大师的回答所暗示的,唯一便携的解决方案是将其转换为使用实体和一对多。

这就是说,Hibernate有一个非规范的功能,称为一个“id袋”,它允许你映射一个基本的或嵌入的收集与每行一个标识符,从而给你你想要的高效更新:

@Entity 
public class Person { 
    @CollectionId(columns={"address_id"}, type="int", generator="increment") 
    @ElementCollection(fetch = FetchType.EAGER) 
    @JoinTable(name = "Person_addresses", joinColumns = @JoinColumn(name = "personid")) 
    private java.util.List<Address> addresses = new java.util.ArrayList<Address>(); 
} 

但请注意从设置到列表的切换。另外注意生成的表结构...看起来非常像一个实体;)