Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.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
Hibernate 双向@OneToOne的问题_Hibernate - Fatal编程技术网

Hibernate 双向@OneToOne的问题

Hibernate 双向@OneToOne的问题,hibernate,Hibernate,我有两个实体客户和地址如下: Customer.java package com.hibernaterecipes.chapter5; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationT

我有两个实体客户和地址如下: Customer.java

package com.hibernaterecipes.chapter5;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="CUSTOMER")
public class Customer {
@Column (name="ID")
@Id
@GeneratedValue (strategy=GenerationType.AUTO)
private Long id;

@Column (name="COUNTRY_CODE")
private String countryCode;

@Column (name="ID_CARD_NO")
private String idCardNo;

@Column (name="FIRST_NAME")
private String firstName;

@Column (name="LAST_NAME")
private String lastName;

@Column (name="EMAIL")
private String email;

@OneToOne (cascade=CascadeType.ALL)
@JoinTable (name="CustomerAddress", 
        joinColumns=@JoinColumn(name="ID"),
        inverseJoinColumns=@JoinColumn(name="ADDRESS_ID"))
private Address address;

public Long getId() {
    return id;
}
public void setId(Long id) {
    this.id = id;
}
public String getCountryCode() {
    return countryCode;
}
public void setCountryCode(String countryCode) {
    this.countryCode = countryCode;
}
public String getIdCardNo() {
    return idCardNo;
}
public void setIdCardNo(String idCardNo) {
    this.idCardNo = idCardNo;
}
public String getFirstName() {
    return firstName;
}
public void setFirstName(String firstName) {
    this.firstName = firstName;
}
public String getLastName() {
    return lastName;
}
public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getEmail() {
    return email;
}
public void setEmail(String email) {
    this.email = email;
}
public Address getAddress() {
    return address;
}
public void setAddress(Address address) {
    this.address = address;
}

}
address.java:

package com.hibernaterecipes.chapter5;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="ADDRESS")
public class Address {
@Id
@Column (name="ADDRESS_ID")
@GeneratedValue (strategy=GenerationType.AUTO)
private Long id;

@Column(name="CITY")
private String city;

@Column(name="STREET")
private String street;

@Column(name="DOOR_PLATE")
private String doorplate;

@OneToOne (mappedBy="address")
private Customer customer;

public Customer getCustomer() {
    return customer;
}
public void setCustomer(Customer customer) {
    this.customer = customer;
}
public Long getId() {
    return id;
}
public void setId(Long id) {
    this.id = id;
}
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public String getStreet() {
    return street;
}
public void setStreet(String street) {
    this.street = street;
}
public String getDoorplate() {
    return doorplate;
}
public void setDoorplate(String doorplate) {
    this.doorplate = doorplate;
}

 }
当我尝试持久化客户时,我会得到以下堆栈跟踪:

Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: com.hibernaterecipes.chapter5.Address.customer
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:412)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:261)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at com.hibernaterecipes.chapter5.Launch5_6A.main(Launch5_6A.java:29)
我曾尝试在@OneToOne中添加@NotNull.optional=false,在@JoinColumn中添加@unique=true,nullable=false,但没有任何效果

帮帮忙。 根据建议,我改变了我的班级地址

package com.hibernaterecipes.chapter5;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="ADDRESS")
public class Address {
@Id
@Column (name="ADDRESS_ID")
@GeneratedValue (strategy=GenerationType.AUTO)
private Long id;

@Column(name="CITY")
private String city;

@Column(name="STREET")
private String street;

@Column(name="DOOR_PLATE")
private String doorplate;

@OneToOne(mappedBy="address")
private Customer customer;

public Customer getCustomer() {
    return customer;
}
public void setCustomer(Customer customer) {
    if (null != customer) {
        customer.setAddress(this);
        this.customer = customer;
    }
}
public Long getId() {
    return id;
}
public void setId(Long id) {
    this.id = id;
}
public String getCity() {
    return city;
}
public void setCity(String city) {
    this.city = city;
}
public String getStreet() {
    return street;
}
public void setStreet(String street) {
    this.street = street;
}
public String getDoorplate() {
    return doorplate;
}
public void setDoorplate(String doorplate) {
    this.doorplate = doorplate;
}
}

客户类别保持不变

用于测试代码助手类 JpaUtil.java

package persistence;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class JpaUtil {
    private static SessionFactory sessionFactory;

      static {
        try {
           sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
           throw new ExceptionInInitializerError(ex);
        }
      }

      public static SessionFactory getSessionFactory() {
          // Alternatively, we could look up in JNDI here
          return sessionFactory;
      }

      public static void shutdown() {
          // Close caches and connection pools
          getSessionFactory().close();
      }
}
用于测试Launch5_6A.java的主类

package com.hibernaterecipes.chapter5;

import org.hibernate.Session;
import org.hibernate.Transaction;

import persistence.JpaUtil;

public class Launch5_6A {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.setCountryCode("India");
        customer.setEmail("subhendu_mahanta@yahoo.com");
        customer.setFirstName("Subhendu");
        customer.setLastName("Mahanta");
        customer.setIdCardNo("43223");
        Address address = new Address();
        address.setCity("Pune");
        address.setDoorplate("E1/33");
        address.setStreet("Paud Road");
        address.setCustomer(customer);
        customer.setAddress(address);

        Session session = JpaUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        session.save(customer);
        tx.commit();
        session.close();

    }

}
结果仍然是一样的

07:54:37,265  INFO Version:15 - Hibernate Annotations 3.2.0.CR3
07:54:37,296  INFO Environment:500 - Hibernate 3.2.0.cr5
...
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: com.hibernaterecipes.chapter5.Address.customer
    at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
    at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
    at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
    at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
    at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
    at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
    at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
    at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:412)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:261)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
    at com.hibernaterecipes.chapter5.Launch5_6A.main(Launch5_6A.java:29)
07:54:39,734  INFO SchemaUpdate:160 - schema update complete
07:54:39,734 DEBUG DriverManagerConnectionProvider:129 - returning connection to pool, pool size: 1
07:54:39,734 DEBUG SessionFactoryImpl:390 - Checking 0 named HQL queries
07:54:39,734 DEBUG SessionFactoryImpl:410 - Checking 0 named SQL queries
07:54:39,796 DEBUG SessionImpl:220 - opened session at timestamp: 12963542797
07:54:39,796 DEBUG JDBCTransaction:54 - begin
07:54:39,796 DEBUG ConnectionManager:415 - opening JDBC connection
07:54:39,796 DEBUG DriverManagerConnectionProvider:93 - total checked-out connections: 0
07:54:39,796 DEBUG DriverManagerConnectionProvider:99 - using pooled JDBC connection, pool size: 0
07:54:39,796 DEBUG JDBCTransaction:59 - current autocommit status: false
07:54:39,796 DEBUG JDBCContext:210 - after transaction begin
07:54:39,796 DEBUG DefaultSaveOrUpdateEventListener:161 - saving transient instance
07:54:39,796 DEBUG AbstractSaveEventListener:152 - saving [com.hibernaterecipes.chapter5.Customer#<null>]
07:54:39,796 DEBUG AbstractSaveEventListener:240 - executing insertions
07:54:39,812 DEBUG Cascade:115 - processing cascade ACTION_SAVE_UPDATE for: com.hibernaterecipes.chapter5.Customer
07:54:39,812 DEBUG CascadingAction:216 - cascading to saveOrUpdate: com.hibernaterecipes.chapter5.Address
07:54:39,812 DEBUG AbstractSaveEventListener:489 - transient instance of: com.hibernaterecipes.chapter5.Address
07:54:39,812 DEBUG DefaultSaveOrUpdateEventListener:161 - saving transient instance
07:54:39,812 DEBUG AbstractSaveEventListener:152 - saving [com.hibernaterecipes.chapter5.Address#<null>]
07:54:39,812 DEBUG AbstractSaveEventListener:240 - executing insertions
07:54:37265信息版本:15-Hibernate注解3.2.0.CR3
07:54:37296信息环境:500-Hibernate 3.2.0.cr5
...
线程“main”org.hibernate.PropertyValueException中的异常:NOTNULL属性引用空值或暂时值:com.hibernaterecipes.chapter5.Address.customer
位于org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
位于org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
位于org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
位于org.hibernate.event.def.AbstractSaveEventListener.SaveWithGenerateId(AbstractSaveEventListener.java:108)
在org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)中
位于org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
位于org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
位于org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
位于org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
位于org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
位于org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
位于org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
位于org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
位于org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
位于org.hibernate.engine.Cascade.Cascade(Cascade.java:130)
位于org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:412)
位于org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:261)
位于org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
位于org.hibernate.event.def.AbstractSaveEventListener.SaveWithGenerateId(AbstractSaveEventListener.java:108)
在org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)中
位于org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
位于org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
位于org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
位于org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
位于org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
位于org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
位于org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
位于com.hibernaterecipes.chapter5.Launch5_6A.main(Launch5_6A.java:29)
07:54:39734信息模式更新:160-模式更新完成
07:54:39734调试驱动程序管理器连接提供程序:129-返回到池的连接,池大小:1
07:54:39734调试SessionFactoryImpl:390-检查0个命名的HQL查询
07:54:39734调试SessionFactoryImpl:410-检查0个命名SQL查询
07:54:39796调试会话MPL:220-在时间戳12963542797处打开的会话
07:54:39796调试JDBCTransaction:54-开始
07:54:39796调试连接管理器:415-打开JDBC连接
07:54:39796调试驱动器管理器连接提供程序:93-已签出的连接总数:0
07:54:39796调试DriverManager连接提供程序:99-使用池化JDBC连接,池大小:0
07:54:39796调试JDBCTransaction:59-当前自动提交状态:false
07:54:39796调试JDBCContext:210-事务开始后
07:54:39796调试DefaultSaveOrUpdateEventListener:161-保存临时实例
07:54:39796调试AbstractSaveEventListener:152-保存[com.hibernaterecipes.chapter5.Customer#]
07:54:39796调试AbstractSaveEventListener:240-执行插入
07:54:39812调试级联:115-处理级联操作\u保存\u更新:com.hibernaterecipes.chapter5.Customer
07:54:39812调试级联操作:216-级联到saveOrUpdate:com.hibernaterecipes.chapter5.Address
07:54:39812调试AbstractSaveEventListener:489-的瞬态实例:com.hibernaterecipes.chapter5.Address
07:54:39812调试DefaultSaveOrUpdateEventListener:161-保存临时实例
07:54:39812调试AbstractSaveEventListener:152-保存[com.hibernaterecipes.chapter5.Address#]
07:54:39812调试AbstractSaveEventListener:240-执行插入

我认为这是Hibernate当前的一个限制(它实际上并没有将空值持久化到DB,因为您使用的是JoinTable,但它认为它是)。我们已经能够在实体中不提取可空/可选标志,而是在数据库模式本身中强制非空性。虽然不太理想,但它可以正常工作,而且您确实可以获得引用完整性(您可以添加prePersist和postLoad侦听器,以确保您甚至不尝试DB写入)。

我认为将地址设置为可嵌入对象会更好地处理这种情况,但这是您的选择

但无论如何,映射一个
@OneToOnepublic class Address {
    @Id @GeneratedValue
    private Long id;

    @Column
    private String name;

    @OneToOne(mappedBy="address")
    private Customer customer;

    public void setCustomer(Customer c) {
        if (null != c) {
            c.setAddress(this);
            this.customer = c;
        }
    }
}

public class Customer {
    @Id @GeneratedValue
    private Long id;

    @Column
    private String name;

    @OneToOne
    @JoinTable(name = "CustomerAddress")
    private Address address;
}
    Customer c = new Customer();
    c.setName("c1");

    Address a = new Address();
    a.setName("a1");

    em.getTransaction().begin();

    em.persist(c);

    a.setCustomer(c);
    em.persist(a);

    em.getTransaction().commit();
Hibernate: insert into Customer (id, name) values (null, ?)
Hibernate: insert into Address (id, name) values (null, ?)
Hibernate: insert into CustomerAddress (address_id, id) values (?, ?)