java Hibernate@OneToOne,带有共享主键(双向)。依赖实体未在数据库中持久化。
我有两个感兴趣的实体(从这里开始称为POI)及其地址。我想定义一个一对一的双向映射,在两者之间使用共享主键,POI作为所有者实体。我使用的是postgreSQL数据库,POI表的POID为PK,由数据库中定义的序列生成器生成。Address table的POID列是Address table的主键,也是FK to POI table的POID列,以及它自己的其他列
**PointOfInterest.java**
@Entity
@Table(name = "\"POI\"")
public class PointOfInterest implements Serializable {
private static final long serialVersionUID = -5406785879200149642L;
@Id
@Column(name="\"POIId\"", nullable=false)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="poi_seq_poiid_generator")
@SequenceGenerator(name = "poi_seq_poiid_generator", sequenceName = "poi_seq_poiid", allocationSize=1)
private Long poiId;
@OneToOne(mappedBy = "poi",cascade = CascadeType.PERSIST)
private Address address;
//Other fields
-----------------------------------------------------------------
**Address.java**
@Entity
@Table(name="\"Address\"")
public class Address implements Serializable{
private static final long serialVersionUID = -7146133528411371107L;
@Id
@GeneratedValue(generator="sharedPrimaryKeyGenerator")
@GenericGenerator(name="sharedPrimaryKeyGenerator",strategy="foreign",parameters = @Parameter(name="property", value="poi"))
@Column(name="\"POIId\"")
private Long poiId;
@OneToOne
@PrimaryKeyJoinColumn
private PointOfInterest poi;
在使用会话保存POI对象之前。保存或更新(poi)。我实例化并设置POI对象的所有其他属性。然后,从我的逻辑中的另一个方法中获取Address对象,并执行类似的操作
PointOfInterest poi = methodCallToGetPOI();
Address address = methodCallToGetAddress();
poi.setAddress(address);
address.setPOI(poi);
//Send POI object to DB layer to an appropriate method which does:
session.saveOrUpdate(poi);
session.flush();
当我看到生成的查询时,我看到如下内容:
Hibernate:
select
nextval ('poi_seq_poiid')
Hibernate:
insert
into
"POI"
("CreatedBy", "CreatedTime", "LocationGeographic", "ModifiedBy", "ModifiedTime", "Name", "POICode", "Radius", "POIType", "POIId")
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
所以,显然hibernate并没有在地址表中生成insert语句。我在互联网上搜索了所有地方,并比较了我的映射,它们似乎是正确的。但是,没有在地址表中插入任何行。调试流时,我发现address对象正在实例化和填充。请帮我弄清楚这是为什么。我能想到这一点的唯一原因是我在使用序列生成器,在互联网上的所有示例和代码片段中,每个人都使用了hibernate的自动生成策略,那么,是因为这个吗?我不能使用自动生成键,我只能使用我的DB序列。如果这些注释不起作用,请建议一些替代方案
我在Spring框架4.0.5版本中使用Spring和Hibernate。发布和从org获得的会话工厂。springframework。奥姆。冬眠4。LocalSessionFactoryBean和事务管理器从org获得。springframework。奥姆。冬眠4。HibernateTransactionManager
# 1 楼答案
经过数小时的代码实验,我们发现这种一对一的双向映射似乎只在cascade=cascadeType时有效。所有都是指定的。我不希望这样,因为在保存POI时,地址字段是由内部API调用填充的,这些调用基于POI的地理位置。所以,当有人试图更新POI时,他们永远不会知道它的地址,因此它将为空。一旦发生更新,这将为特定POI将地址表行设置为null。但是,我现在会做一个变通。然而,仍然不确定为什么必须给出cascadeType。所有这些都是为了这样一个映射。这当然是合乎逻辑的,但并不能解释为什么是级联型。坚持不行
此外,我使用的@GenericGenerator等映射是特定于hibernate的,因此这段代码以特定于hibernate的方式而不是JPA进行映射。此外,@GenericGenerator只是告诉hibernate它应该用它的序列为POI生成的Id来填充地址的Id
# 2 楼答案
你也不想在地址上生成PK(即使是使用特殊生成器)
由于这两个实体共享PK,因此生成可能只发生一次。然后映射必须负责用相同的值填充
POI_ID
和ADDRESS_ID
奇怪的是,
@PrimaryKeyJoinColumn
在Hibernate 5.2.2上不再工作了,但这里有一个等价的映射:使用Hibernate DDL生成,结果如下: