JPA ne sauvegarde pas la clé étrangère dans la relation @OneToMany
Question
J'utilise Spring avec Hibernate en tant que fournisseur JPA et j'essaie d'obtenir un @OneToMany (un contact ayant plusieurs numéros de téléphone) pour enregistrer la clé étrangère dans le tableau des numéros de téléphone. Dans mon formulaire, j’obtiens un objet Contact contenant une liste de numéros de téléphone. Le contact persiste correctement (Hibernate récupère une PK de la séquence spécifiée). La liste des numéros de téléphone (numéros) est également conservée avec un PK correct, mais il n'y a pas de FK dans la table Contacts.
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;
}
}
J'espère que tous les éléments pertinents ci-dessus ont été cités, sinon veuillez me le faire savoir.
La solution
Vous devez gérer vous-même les relations Java. Pour ce genre de chose, vous avez besoin de quelque chose comme:
@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;
...
}
Autres conseils
En réponse à la réponse de Cletus. Je dirais qu'il est important d'avoir l'annotation @column
sur les champs id, ainsi que tous les éléments de séquence. Une alternative à l'utilisation du paramètre mappedBy de l'annotation @OneToMany
consiste à utiliser l'annotation @JoinColumn
.
Par ailleurs, votre implémentation d’addPhone doit être examinée. Ce devrait probablement être quelque chose comme.
public void addPhone(PhoneNumber phone) {
if (phone == null) {
return;
} else {
if (phoneNumbers == null) {
phoneNumbers = new ArrayList<Phone>();
}
phoneNumbers.add(phone);
phone.setContact(this);
}
}
Si la relation contact-téléphone est unidirectionnelle, vous pouvez également remplacer mappéPar
dans @OneToMany
par l'annotation @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;
...
}
Similaire à JPA @OneToMany - > Parent - Référence de l'enfant (clé étrangère)
Je ne pense pas que la méthode addPhone soit nécessaire, il vous suffit de définir le contact dans l'objet téléphone:
phone.setContact(contact);