java - relacion - onetomany jpa ejemplo
Relaciones JPA OneToMany y ManyToOne (3)
Como expliqué en este artículo y en mi libro Persistencia de Java de alto rendimiento , nunca debería usar la anotación unidireccional @OneToMany
porque:
- Genera declaraciones SQL ineficientes
- Crea una tabla adicional que aumenta la huella de memoria de sus índices de base de datos
Ahora, en su primer ejemplo, ambas partes son propietarias de la asociación, y esto es malo .
Si bien @JoinColumn
dejaría al lado @OneToMany
a cargo de la asociación, definitivamente no es la mejor opción. Por lo tanto, siempre use el atributo mappedBy
en el lado @OneToMany
.
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
public List<APost> aPosts;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
public List<BPost> bPosts;
}
public class BPost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
public class APost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
Tengo tres clases, uno de los cuales es User y este usuario tiene otras instancias de clases. Me gusta esto;
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
public List<APost> aPosts;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
public List<BPost> bPosts;
}
public class BPost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
public class APost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
public User user;
}
funciona así pero genera tablas emty en db. Que debe contener claves foráneas Cuando traté de usar mappedBy y JoinColumn anotar, fallé. ¿Cómo puedo resolver esto?
Información extra:
Cuando cambié con;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="id")
public User user;
y
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="id")
public List<APost> aPosts;
Me estoy poniendo
Se produjo un error de JPA (no se puede construir EntityManagerFactory): Columna repetida en el mapeo de la entidad: columna models.post.APost: id (debe correlacionarse con insert = "false" update = "false")
Edición final: Finalmente, estaba totalmente equivocado acerca de las anotaciones jpa. :( Cuando cambio
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="id")
a
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
y
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id")
Todo funciona bien. :)
Como va a guardar APost y BPost directamente, esto significa que APost y BPost serán propietarios de la relación. Como el usuario no posee la relación, habrá un atributo mapeadoBy en la anotación @OneToMany.
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,mappedBy="user", targetEntity = APost.class)
public List<APost> aPosts;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,mappedBy="user", targetEntity = BPost.class)
public List<BPost> bPosts;
}
public class BPost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id",referencedColumnName="id")
public User user;
}
public class APost extends Post {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id",referencedColumnName="id")
public User user;
}
La anotación @JoinColumn será responsable de agregar la clave externa en Apost y BPost.
No estoy muy seguro de su pregunta (el significado de "tabla vacía", etc., o cómo mappedBy
y JoinColumn
no estaban funcionando).
Creo que estabas tratando de hacer una relación bidireccional.
En primer lugar, debe decidir qué lado "posee" la relación. Hibernate va a configurar la base de relaciones en ese lado. Por ejemplo, supongamos que hago que el lado del Post
dueño de la relación (simplifico su ejemplo, solo para mantener las cosas al punto), el mapeo se verá así:
(Ojalá la sintaxis sea correcta. Los estoy escribiendo solo por memoria. Sin embargo, la idea debería estar bien)
public class User{
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
private List<Post> posts;
}
public class Post {
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id")
private User user;
}
Al hacerlo, la tabla para Post
tendrá una columna user_id
que almacenará la relación. Hibernate está obteniendo la relación por parte del user
en la Post
(en lugar de las posts
en el User
. Notará la diferencia si tiene el user
Post
pero le faltan las posts
User
).
Has mencionado mappedBy
y JoinColumn
no funciona. Sin embargo, creo que esta es, de hecho, la forma correcta. Dígale si este enfoque no funciona para usted y proporciónenos un poco más de información sobre el problema. Creo que el problema se debe a algo más.
Editar:
Solo un poco de información adicional sobre el uso de mappedBy
ya que generalmente es confuso al principio. En mappedBy
, colocamos el "nombre de propiedad" en el lado opuesto de la relación bidireccional, no en el nombre de columna de la tabla.