Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用共享主键(双向)休眠@OneToOne。依赖实体未在数据库中持久化。_Java_Spring_Hibernate_One To One_Bidirectional - Fatal编程技术网

Java 使用共享主键(双向)休眠@OneToOne。依赖实体未在数据库中持久化。

Java 使用共享主键(双向)休眠@OneToOne。依赖实体未在数据库中持久化。,java,spring,hibernate,one-to-one,bidirectional,Java,Spring,Hibernate,One To One,Bidirectional,我有两个感兴趣的实体(从这里开始称为POI)及其地址。我想定义一个一对一的双向映射,在两者之间使用共享主键,POI作为所有者实体。我使用的是postgreSQL数据库,POI表的POID为PK,由数据库中定义的序列生成器生成。地址表的POID列是地址表的主键,也是FK到POI表的POID列,以及它自己的其他列 **PointOfInterest.java** @Entity @Table(name = "\"POI\"") public class PointOfInterest imple

我有两个感兴趣的实体(从这里开始称为POI)及其地址。我想定义一个一对一的双向映射,在两者之间使用共享主键,POI作为所有者实体。我使用的是postgreSQL数据库,POI表的POID为PK,由数据库中定义的序列生成器生成。地址表的POID列是地址表的主键,也是FK到POI表的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;
在使用session.saveOrUpdate(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 framework 4.0.5.RELEASE中使用Spring和Hibernate,从org.springframework.orm.hibernate4.LocalSessionFactoryBean获得会话工厂,从org.springframework.orm.hibernate4.HibernateTransactionManager获得事务管理器。

您不想在地址上生成PK(即使使用特殊生成器)

由于这两个实体共享PK,生成可能只发生一次。然后映射必须负责用相同的值填充
POI\u ID
ADDRESS\u ID

奇怪的是,
@PrimaryKeyJoinColumn
不再适用于Hibernate 5.2.2,但这里有一个等价的映射:

@Entity
@Table(name = "POI")
public class PointOfInterest implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "poi_seq_poiid_generator")
    @SequenceGenerator(name = "poi_seq_poiid_generator", sequenceName = "poi_seq_poiid", allocationSize = 1)
    @Column(name = "POI_ID")
    private Long id;

    @OneToOne(mappedBy = "poi", cascade = CascadeType.ALL, orphanRemoval = true)
    private Address address;

    @Column
    private String name;

    ...
}

@Entity
@Table(name = "Address")
public class Address implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @OneToOne
    @JoinColumn(name = "ADDRESS_ID")
    private PointOfInterest poi;

    @Column
    private String name;

    ...
}
使用Hibernate DDL生成,这是生成的SQL:

create table Address (name varchar(255), ADDRESS_ID bigint not null, primary key (ADDRESS_ID)) ENGINE=InnoDB
create table POI (POI_ID bigint not null, name varchar(255), primary key (POI_ID)) ENGINE=InnoDB
alter table Address add constraint FK_Address_ADDRESS_ID foreign key (ADDRESS_ID) references POI (POI_ID)

经过数小时的代码实验,我发现这种一对一的双向映射似乎只有在指定了cascade=cascadeType.ALL时才起作用。我不想这样做,因为在保存POI时,地址字段是由基于POI地理位置的内部API调用填充的。因此,当有人试图更新POI时,他们永远不会更新POI知道它的地址,因此它将为空。一旦发生更新,这将为该特定POI将地址表行设置为空。但是,现在将对此进行解决。但是,仍然不确定为什么必须为此类映射指定cascadeType.ALL。这肯定是符合逻辑的,但没有解释cascadeType.PERSIST为什么不起作用


此外,我使用的@GenericGenerator等映射是特定于hibernate的,因此此代码以特定于hibernate的方式而不是JPA进行映射。此外,@GenericGenerator只是告诉hibernate,它应该用为POI按顺序生成的Id来填充地址Id。

您好,谢谢您的回答,但是问题没有得到解决。只有PointOfItnerest实体被填充。你能详细说明一下,为什么不需要临时生成器吗?你是对的,我在Hibernate 5.2.2上对它进行了测试,但它已经不工作了。请参阅更新以获得一个处理ID引用的替代映射。请注意,我只测试了DDL生成,不知道添加ress id在运行时自动填充(但它应该会自动填充)。感谢您的编辑:)我确实让它工作了。刚刚将cascadeType更改为cascadeType。突然,地址行被插入。