java - unidirectional - many to one one to many example
JPA no guarda la clave externa en la relación @OneToMany (4)
Estoy usando Spring con Hibernate como proveedor de JPA y estoy tratando de obtener un @OneToMany (un contacto que tiene muchos números de teléfono) para guardar la clave externa en la tabla de números de teléfono. De mi formulario obtengo un objeto de contacto que tiene una lista de teléfonos (números) en él. El contacto se conserva correctamente (Hibernate obtiene un PK de la secuencia especificada). La lista de Teléfonos (números) también se conserva con una PK correcta, pero no hay FK en la tabla de Contactos.
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;
}
}
Ojalá haya obtenido todos los datos relevantes anteriores, de lo contrario, hágamelo saber.
En respuesta a la respuesta de Cletus. Yo diría que es importante tener la anotación @column
en los campos de identificación, así como todas las cosas de la secuencia. Una alternativa al uso del parámetro mappedBy de la anotación @OneToMany
es usar la anotación @JoinColumn
.
Como un poco aparte de su implementación de addPhone necesita mirar. Probablemente debería ser algo así.
public void addPhone(PhoneNumber phone) {
if (phone == null) {
return;
} else {
if (phoneNumbers == null) {
phoneNumbers = new ArrayList<Phone>();
}
phoneNumbers.add(phone);
phone.setContact(this);
}
}
No creo que el método addPhone sea necesario, solo tiene que configurar el contacto en el objeto del teléfono:
phone.setContact(contact);
Si la relación Contacto-Teléfono es unidireccional, también puede reemplazar mappedBy
en la anotación @JoinColumn(name = "contact_id")
con @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 en JPA @OneToMany -> Parent - Child Reference (Foreign Key)
Tienes que gestionar las relaciones de Java a ti mismo. Para este tipo de cosas necesitas algo como:
@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;
...
}