How to populate foreign key values in a Hibernate + Spring JPA configuration when parent/child objects are persisted at the same time?

11,185

That code has two things preventing it from working:

  1. Your entities have no @Id. You probably just left it off because this is an example, but it's worth pointing out.
  2. You've double-mapped the column parent_id. Child has both a Long field and a Parent field mapped to the same column. Get rid of the Long. It's the Parent relationship you're after.

After that, what you have there is a completely traditional bidirectional one-to-many with a join column. If it's not working for you, then you're doing something wrong in the code where you create and save them. Very probably, you're not creating the objects properly. Correct code using these entities would look something like this:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Parent p = new Parent();
Child child = new Child();
child.parent = p;
Child child1 = new Child();
child1.parent = p;
p.children = Arrays.asList(child, child1);
session.save(p);
session.save(p.children.get(0));
session.save(p.children.get(1));
tx.commit();

Note especially that the child should be set in the parent as well as the parent in the child. Don't build a half-broken object model and expect Hibernate to clean up your mess. Many people ignore this seemingly obvious requirement and wonder why Hibernate seems unstable and/or unreliable.

Share:
11,185
skel625
Author by

skel625

Updated on July 13, 2022

Comments

  • skel625
    skel625 almost 2 years

    I have two objects, Parent and Child. Child has a foreign key back to PARENT_ID field in PARENT table (MySQL database).

    When a Parent and Child object are created/assembled at the same time, and persist is called, the Child PARENT_ID foreign key is not automatically populated.

    Sample Code:

    @Entity
    @Table(name = "PARENT")
    public class Parent {
        @Column(name = "PARENT_ID")
        private Long parentId;
    
        @OneToMany(mappedBy = "parent")
        private List<Child> children;
    }
    
    @Entity
    @Table(name = "CHILD")
    public class Child {
        @Column(name = "CHILD_ID")
        private Long childId;
    
        @Column(name = "PARENT_ID")
        private Long parentId;
    
        @ManyToOne
        @JoinColumn(name = "parent_id")
        private Parent parent;
    }
    

    I have two samples for persistence:

    1) Using a Hibernate EntityManager:

    @PersistenceContext
    EntityManager em;
    
    ...
    
    em.persist(parent);
    

    2) Using a Spring Data JPA JpaRepository instance:

    public interface ParentRepository extends JpaRepository<Parent, Long> {
    
    }
    

    And in my ParentServiceImpl:

    @Autowired
    private ParentRepository parentRepository;
    
    ...
    
    public Parent save(Parent parent) {
        return parentRepository.save(parent);
    }
    

    What is the recommended strategy to go about populating the foreign key? Should the Parent object be persisted first and then the Child object foreign key set at that point? Or is there a way to persist it all at once with the foreign key being set automatically or by reference?

    Edit: Persistence samples added.

    Edit 2 (fixed!): Problem solved as per Ryan Stewart's second point. I removed the Long parentId field from the Child object and put the @Column reference for the parentId on the getter. Also made sure to set-up references correctly (importantly Child reference back to Parent).