NA.
NA.

Reputation: 6579

JPA not saving foreign key to @OneToMany relation

I'm using Spring with Hibernate as a JPA provider and are trying to get a @OneToMany (a contact having many phonenumbers) to save the foreign key in the phone numbers table. From my form i get a Contact object that have a list of Phone(numbers) in it. The Contact get persisted properly (Hibernate fetches an PK from the specified sequence). The list of Phone(numbers) also gets persisted with a correct PK, but there's no FK to the Contacts table.

public class Contact implements Serializable {

    @OneToMany(mappedBy = "contactId", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
    private List<Phone> phoneList;

}

public class Phone implements Serializable {

    @JoinColumn(name = "contact_id", referencedColumnName = "contact_id")
    @ManyToOne
    private Contact contactId;

}

@Repository("contactDao")
@Transactional(readOnly = true)
public class ContactDaoImpl implements ContactDao {

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void save(Contact c) {
        em.persist(c);
        em.flush();
    }
}


@Controller
public class ContactController {
    @RequestMapping(value = "/contact/new", method = RequestMethod.POST)
    public ModelAndView newContact(Contact c) {
        ModelAndView mv = new ModelAndView("contactForm");
        contactDao.save(c);
        mv.addObject("contact", c);
        return mv;
    }
}

Hopefully I got all of the relevant bits above, otherwise please let me know.

Upvotes: 22

Views: 52340

Answers (7)

Saibanna Biradar
Saibanna Biradar

Reputation: 21

In JPA this helped me

contact.getPhoneList().forEach(pl -> pl.setContact(contact));
contactRepository.save(contact);

Upvotes: 0

Ilya Lysenko
Ilya Lysenko

Reputation: 1892

Try this sample:

@Entity
public class Contact {
    @Id
    private Long id;

    @JoinColumn(name = "contactId")
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Phone> phones;
}

@Entity
public class Phone {
    @Id
    private Long id;
    private Long contactId;
}

Upvotes: 0

Tom Chamberlain
Tom Chamberlain

Reputation: 3065

If you want your relationship unidirectional i.e. can navigate from Contact to Phone's only, you need to add

@JoinColumn(name = "contact_id", nullable = false)

Under your @OneToMany on your parent entity.

nullable = false IS VITAL if you want hibernate to populate the fk on the child table

Upvotes: 1

cletus
cletus

Reputation: 625017

You have to manage the Java relationships yourself. For this kind of thing you need something like:

@Entity
public class Contact {
  @Id
  private Long id;

  @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "contact")
  private List<Phone> phoneNumbers;

  public void addPhone(PhoneNumber phone) {
     if (phone != null) {
        if (phoneNumbers == null) {
            phoneNumbers = new ArrayList<Phone>();          
        }
        phoneNumbers.add(phone);
        phone.setContact(this);
     }
  }

  ...
}

@Entity
public class Phone {
  @Id
  private Long id;

  @ManyToOne
  private Contact contact;

  ...
}

Upvotes: 31

Camel
Camel

Reputation: 21

I don't think the addPhone method is necessary, you only have to set the contact in the phone object:

phone.setContact(contact);

Upvotes: 2

samsong8610
samsong8610

Reputation: 137

If the Contact-Phone relationship is unidirectional, you can also replace mappedBy in @OneToMany annotation with @JoinColumn(name = "contact_id").

@Entity
public class Contact {
  @Id
  private Long id;

  @OneToMany(cascade = CascadeType.PERSIST)
  @JoinColumn(name = "contact_id")
  private List<Phone> phoneNumbers;

  // normal getter/setter
  ...
}

@Entity
public class PhoneNumber {
  @Id
  private Long id;

  ...
}

Similar in JPA @OneToMany -> Parent - Child Reference (Foreign Key)

Upvotes: 5

mR_fr0g
mR_fr0g

Reputation: 8722

In reply to Cletus' answer. I would say that it's important to have the @column annotation on the id fields, as well as all the sequence stuff. An alternative to using the mappedBy parameter of the @OneToMany annotation is to use the @JoinColumn annotation.

As a kinda aside your implementation of addPhone needs looking at. It should probably be something like.

public void addPhone(PhoneNumber phone) {
    if (phone == null) {
        return;
    } else {
        if (phoneNumbers == null) {
            phoneNumbers = new ArrayList<Phone>();
        }
        phoneNumbers.add(phone);
        phone.setContact(this);
    }
}

Upvotes: 6

Related Questions