Not-null属性引用持久值的null或transient值

时间:2014-11-24 19:38:13

标签: java hibernate jpa orm hibernate-mapping

我试图使用JPA1来持久化两个不同的实体,并使用Hibernate实现。 代码如下所示:

父实体类

@Entity
@Table(name = "parent")
public class Parent implements Serializable {

    {...}
    private Child child;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "child_id", nullable = "false")
    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
}

子实体类

@Entity
@Table(name = "child")
public class Child implements Serializable {

    private Integer id;

    @Id
    @Column(name = "child_id")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

测试用例

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/application.xml")
@Transactional
public class ParentTest extends TestCase {

    @PersistenceContext
    private EntityManager entityManager;

    @Test
    public void testSave() {
        Child child = new Child();
        child.setId(1);

        Parent parent = new Parent();
        parent.setChild(child);

        entityManager.persist(parent.getChild());
        entityManager.persist(parent); // throws the exception
    }
}

application.xml上的实体管理器和事务

<tx:annotation-driven transaction-manager="transactionManager" /> 

<jee:jndi-lookup id="dataSource" jndi-name="java:/jdbc/myds" expected-type="javax.sql.DataSource" /> 

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="packagesToScan" value="com.mypackage" />
    <property name="dataSource" ref="dataSource" /> 
    <property name="jpaVendorAdapter"› 
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect>org.hibernate.dialect.Oracle10gDialect</prop>
        </props>
    </property>
</bean> 

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" /> 
</bean>

当尝试插入父对象时,hibernate抛出一个PropertyValueException,表示child为null或者是瞬态,即使在此操作之前创建并保留了child。奇怪的是,这只能在单元测试中失败,而在实际应用中,使用预先插入的子节点,这可以正常工作。

PS: 我很清楚我可以通过级联持久来映射孩子,但这不是这里的想法。我只想检查这两个是否独立工作。

7 个答案:

答案 0 :(得分:8)

这里的问题是您使用设置的值来持久保存父表。 当它持久化时,它需要子表id,因为它是一个外键,因此它必须被持久化,因此它是一个非null属性引用一个空值。

    @Test
    public void testSave() {
        Child child = new Child();
        child.setId(1);
        entityManager.persist(child); 

        Parent parent = new Parent();
        parent.setChild(child);

        entityManager.persist(parent); 
    }

尝试此操作首先保存子项,然后保存父项。继续更改映射

答案 1 :(得分:2)

除了父母与子女问题的FK之外,持续性命令是导致您的问题的原因。

您的问题是related to flushing。仅仅因为您指示Hibernate持久化对象,并不意味着它会自动满足您的请求。持久化请求仅进入操作队列,以便在刷新时实现。所以你的第二个持久化只是找到没有实际“持久”Child的Parent实体。

您可以按如下方式修改代码:

    Child child = new Child();
    child.setId(1);

    entityManager.persist(parent.getChild());
    entityManager.flush();

    Parent parent = new Parent();
    parent.setChild(child);
    entityManager.persist(parent);
    entityManager.flush;

答案 2 :(得分:2)

首先你在Parent中使用@ManyToOne告诉我你有一个Child对象有多个父对象,我想情况并非如此。

根据你的类结构,我可以理解你在Parent和Child实体之间有一个OneToOne映射。

关于异常,您是否有理由不使用Parent和Child之间的级联来自动处理保存,更新和删除的映射?如果您没有考虑过它,可以通过设置以下配置来尝试:Example Parent/Child - Hibernate

cascade = {CascadeType.ALL}

虽然我建议在Child和Parent之间更改ManyToOne到OneToOne的映射。

请告诉我。

答案 3 :(得分:1)

试试这个:

@ManyToOne(fetch = FetchType.LAZY,optional=false)
@JoinColun(name = "child_id", nullable = "false")
public Child getChild() {
    return child;
}

答案 4 :(得分:0)

某些字段设置为not-null="true",您必须在保存到db之前为其提供值。 对于父表和子表中的所有字段,设置具有适当值的所有非空字段

答案 5 :(得分:0)

尝试为@ManyToOne(fetch = FetchType.LAZY,cascade=PERSIST, mappedBy="parent")提供public Child getChild()并仅保留父对象。两者都将保留。

答案 6 :(得分:0)

我遇到了类似的问题,我在测试中遇到了一个错误,说“ not-null属性引用的是null或瞬态值”,但在正常运行应用程序时却没有。

原来,我只需要向hibernate.properties文件中添加一行即可:

hibernate.check_nullability=false

由于某种原因,在运行应用程序时,此选项默认设置为false,但在测试时为true。将其添加到hibernate.properties不会影响正在运行的应用程序,但可以修复测试。