Estoy tratando de tener 2 campos de la misma clase de dominio en mi entidad y recibo este error:
org.hibernate.MappingException: no se pudo determinar el tipo para: com.packt.webapp.domain.User, en la tabla: opiniones, para las columnas: [org.hibernate.mapping.Column(author)]
Mis entidades:
@Entity @Table(name="opinions") public class Opinion { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @NotNull private String text; @NotNull private String date; @ManyToOne @JoinColumn(name="commented_user") private User writtenTo; private User author; @Entity @Table(name="user") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String username; private String password; @OneToMany(mappedBy="writtenTo") private List<Opinion> opinions; Solo quiero asignar opiniones a usuarios comentados y almacenar el autor del comentario en el campo del author . Cuando elimino el campo de author , todo funciona. ¿Qué tiene de malo este ejemplo?
¿Intentar anotar también el autor?
@ManyToOne @JoinColumn(name="author") private User author;Se queja de que no sabe cómo mapear el campo del author . Puede proporcionar una asignación similar a cómo asignó writtenTo . Una opinión tiene un autor y un autor puede haber escrito muchas opiniones.
Si desea ignorar un campo para el mapeo, anótelo con @Transient . La anotación transitoria evita que ese campo se conserve en la base de datos; de lo contrario, debe asignarlo así:
Entidad de opinión:
@Entity @Table(name="opinions") public class Opinion { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @NotNull private String text; @NotNull private String date; @ManyToOne @JoinColumn(name="commented_user") private User writtenTo; // map author to User entity @ManyToOne @JoinColumn(name="authored_user") private User author; // getters and setters }Entidad usuaria:
@Entity @Table(name="user") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String username; private String password; @OneToMany(mappedBy="writtenTo") private List<Opinion> opinions; // map opinions to the author @OneToMany(mappedBy="author") private List<Opinion> authoredOpinions; // getters and setters }Simplemente aplique la anotación @ManyToOne en ambos campos de usuario.
@ManyToOne @JoinColumn(name="commented_user") private User writtenTo; @ManyToOne @JoinColumn(name="author") private User author;Pero hay una solución más flexible para problemas como este. Reemplace las relaciones @OneToMany y @ManyToOne por las de @ManyToMany. Cree una entidad Usuario y Rol (con descendientes para los que tienen campos específicos). Un usuario puede tener muchos roles (escritor, autor, etc.) y muchos usuarios pueden desempeñar un rol. En este caso, puede cambiar de opinión y crear/eliminar/adjuntar/separar roles dinámicamente sin que cambie la estructura de datos en las tablas existentes.
@Entity public class User { @Id private Long id; @Column private String name; @ManyToMany @JoinTable( name="User_Role", joinColumns=@JoinColumn(name="UserID", referencedColumnName="ID"), inverseJoinColumns=@JoinColumn(name="RoleID", referencedColumnName="ID")) private List<Role> roles; } @Entity public class Role { @Id private Long id; @Column private String name; @ManyToMany( mappedBy="roles" ) private List<User> users; }Y puede obtener/verificar los roles de usuario por ID/nombre de rol usando una clase de utilidad:
puclic class RoleUtility { public Role getUserRoleByName( User user_, String roleName_ ) { User retRole = null; Iterator<Role> i = roles_.iterator(); while ( ( retRole == null ) && i.hasNext() ) { Role role = (Role) i.next(); if ( roleName_.isEqual( role.getName ) ) retRole = role; } return retRole; } }El código de cliente para verificar un rol:
User user = ... Role role = RoleUtility.getRoleByName( user.getRoles(), roleName );Quédese en su ejemplo con esta solución, puede agregar un censor/moderador a la opinión o algo así sin que cambie la estructura de datos.