Not-null property references a null or transient value for persisted value

51,344

Solution 1

The problem here is you are persisting the parent table with the values set . When it goes to persist it needs the child table id which has to be persisted already as it was a foreign key and hence it was a not null property references a null value.

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

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

        entityManager.persist(parent); 
    }

Try this to save the child first and then parent .Else changing the mapping

Solution 2

First thing you are using @ManyToOne in Parent which tells me that you are having more than one parent for one Child object, I guess that is not the case.

As per your class structure I can understand that you have OneToOne mapping between Parent and Child entities.

Regarding the exception is there a reason you are not using cascades between Parent and Child to handle the mapping automatically for the save, update and delete ? If you have not thought about it than you can give it a try by setting below configuration as specified here : Example Parent/Child - Hibernate

cascade = {CascadeType.ALL}

Though I would suggest to change the mapping from ManyToOne to OneToOne between Child and Parent.

Please let me know.

Solution 3

Aside from having a Parent with a FK to a Child issue, the persist order is what causes your issue.

Your problem is related to flushing. Just because you instructed Hibernate to persist an object, it doesn't mean it automatically serves your request. The persist request goes to an action queue only to be materialized at flush time. So your second persist simply find the Parent entity without an actual "persisted" Child.

You can simply fix your code as follows:

    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;

Solution 4

Try this:

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

Related videos on Youtube

renke
Author by

renke

Updated on March 07, 2020

Comments

  • renke
    renke about 4 years

    I'm trying to persist two different entities using JPA1, with the Hibernate implementation. The code for this is as shown below:

    Parent entity class

    @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;
    }
    

    Child entity class

    @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;
        }
    }
    

    Test case

    @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
        }
    }
    

    Entity manager and transaction on 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>
    

    When trying to insert the parent object, hibernate throws a PropertyValueException, saying child is null or transient, even though child was created and persisted before this operation. The odd thing is this only fails on the unit test, and in the real application, with a pre-inserted child, this works just as expected.

    PS: I'm pretty aware I could map child with cascade persist, but that's not the idea here. I just want to check if these two work independently.

    • Predrag Maric
      Predrag Maric over 9 years
      What type is EntityManager? I can't find any reference to insert() method.
    • santedicola
      santedicola over 9 years
      I think it might be related to the transaction handling in the Junit method. The parent can only be inserted if the child is already in the database (after a commit). That would explain why it works on your "real" application an not here. Can you share your application.xml file?
    • renke
      renke over 9 years
      @PredragMaric my bad. I'm using the persist method. Fixed on the post.
    • renke
      renke over 9 years
      @santedicola added the transaction and entity manager config from application.xml
    • Dudelilama
      Dudelilama over 9 years
      Can you show us the stack trace?
    • Cassidy Laidlaw
      Cassidy Laidlaw over 4 years
      @renke did you ever find a solution to this?
    • renke
      renke about 4 years
      @CassidyLaidlaw I stopped using hibernate :)
  • renke
    renke over 9 years
    In the snippet provided, I persist child before the parent as well, with the only difference you set the child after it is persisted. This doesn't do anything different from what I done, since I keep the reference to child and the relationship mapping is not bi-directional.
  • renke
    renke over 9 years
    In this case, child has a manually set id, thus does not need to be flushed to the database to be available and become persistent in the context. Even though, I tried flushing the entity manager after every persist, and still had no luck.
  • renke
    renke over 9 years
    ... which is exactly what I'm doing.