JPA не сохраняет внешний ключ в отношении @OneToMany
Вопрос
Я использую Spring с Hibernate в качестве поставщика JPA и пытаюсь получить @OneToMany (контакт, имеющий много телефонных номеров), чтобы сохранить внешний ключ в таблице телефонных номеров. Из моей формы я получаю контактный объект, в котором есть список номеров телефонов. Контакт сохраняется правильно (Hibernate выбирает PK из указанной последовательности). Список телефонов (номеров) также сохраняется с правильным PK, но в таблице контактов нет FK. Р>
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;
}
}
Надеюсь, я получил все соответствующие биты выше, в противном случае, пожалуйста, дайте мне знать.
Решение
Вы должны сами управлять отношениями Java. Для такого рода вещей вам нужно что-то вроде:
@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;
...
}
Другие советы
В ответ на ответ Клетуса. Я бы сказал, что важно иметь аннотацию @column
для полей id, а также для всей последовательности. Альтернативой использованию параметра mappedBy аннотации @OneToMany
является использование аннотации @JoinColumn
. Р>
В качестве своего рода стороннего подхода необходимо рассмотреть реализацию вашего addPhone. Вероятно, это должно быть что-то вроде.
public void addPhone(PhoneNumber phone) {
if (phone == null) {
return;
} else {
if (phoneNumbers == null) {
phoneNumbers = new ArrayList<Phone>();
}
phoneNumbers.add(phone);
phone.setContact(this);
}
}
Если отношение Контакт-телефон является однонаправленным, вы также можете заменить mappedBy
в аннотации @OneToMany
на @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;
...
}
Похоже на JPA @OneToMany - > Родитель - ссылка на ребенка (внешний ключ)
Я не думаю, что метод addPhone необходим, вам нужно всего лишь установить контакт в объекте телефона:
phone.setContact(contact);