我遇到了多对多关系的问题。人可以有一些角色,每个角色都与某些人有关。因此,当hibernate持久化时,整个实体会尝试插入与退出的人相关的角色。
这是堆栈跟踪
ep 18, 2016 7:52:02 PM org.apache.coyote.AbstractProtocol start
INFORMACIÓN: Starting ProtocolHandler ["ajp-nio-8009"]
sep 18, 2016 7:52:02 PM org.apache.catalina.startup.Catalina start
INFORMACIÓN: Server startup in 14614 ms
Hibernate:
insert
into
CLIENTE
(ALIAS, DESCRIPCION, EDAD_MAX, EDAD_MIN, VALORACION)
values
(?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
PERSONA
(APELLIDOS, ID_CLIENTE, IS_CLIENTE, FECHA_NACIMIENTO, LOCALIDAD, MAIL, NOMBRE, PASSWORD, SEXO, TELEFONO, USUARIO)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
USER_PROFILE
(TIPO)
values
(?)
sep 18, 2016 7:58:17 PM org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: El Servlet.service() para el servlet [dispatcher] en el contexto con ruta [/aphroditesocial] lanzó la excepción [Request processing failed; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] con causa raíz
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'CLIENTE' for key 'TIPO'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
我有那些实体
@Component
@Entity
@Table(name = "PERSONA")
public class PersonalData implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -4725368930330921397L;
@Id
@Column(name = "ID_PERSONA", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id = 0;
@Column(name = "NOMBRE", nullable = false)
private String nombre;
@Column(name = "APELLIDOS", nullable = false)
private String apellidos;
@Column(name = "FECHA_NACIMIENTO", nullable = false)
private String fechaNacimiento;
@Column(name = "MAIL", nullable = false)
private String mail;
@Column(name = "USUARIO", nullable = false, unique=true)
private String usuario;
@Column(name = "PASSWORD", nullable = false)
private String password;
@Column(name = "TELEFONO", nullable = false)
private String telefono;
@Column(name = "SEXO", nullable = false)
private String sexo;
@Column(name = "IS_CLIENTE", nullable = false)
private boolean cliente;
@Column(name = "LOCALIDAD", nullable = false)
private String localidad;
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name="ID_CLIENTE")
private ClientData clientData;
@NotEmpty
@ManyToMany(
fetch = FetchType.LAZY
, cascade = CascadeType.ALL
)
@JoinTable(name = "PERSONA_USER_PROFILE",
joinColumns = { @JoinColumn(name = "ID_PERSONA"
//, referencedColumnName="ID_PERSONA"
)},
inverseJoinColumns = { @JoinColumn(name = "ID_USER_PROFILE") })
private Set<UserProfile> userProfiles = new HashSet<UserProfile>();
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getApellidos() {
return apellidos;
}
public void setApellidos(String apellidos) {
this.apellidos = apellidos;
}
public String getFechaNacimiento() {
return fechaNacimiento;
}
public void setFechaNacimiento(String fechaNacimiento) {
this.fechaNacimiento = fechaNacimiento;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getUsuario() {
return usuario;
}
public void setUsuario(String usuario) {
this.usuario = usuario;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTelefono() {
return telefono;
}
public void setTelefono(String telefono) {
this.telefono = telefono;
}
public String getSexo() {
return sexo;
}
public void setSexo(String sexo) {
this.sexo = sexo;
}
public boolean isCliente() {
return cliente;
}
public void setCliente(boolean cliente) {
this.cliente = cliente;
}
public String getLocalidad() {
return localidad;
}
public void setLocalidad(String localidad) {
this.localidad = localidad;
}
public ClientData getClientData() {
return clientData;
}
public void setClientData(ClientData clientData) {
this.clientData = clientData;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<UserProfile> getUserProfiles() {
return userProfiles;
}
public void setUserProfiles(Set<UserProfile> userProfiles) {
this.userProfiles = userProfiles;
}
@Override
public String toString() {
return "PersonalData [id=" + id + ", nombre=" + nombre + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((usuario == null) ? 0 : usuario.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PersonalData other = (PersonalData) obj;
if (id != other.id)
return false;
if (usuario == null) {
if (other.usuario != null)
return false;
} else if (!usuario.equals(other.usuario))
return false;
return true;
}
}
用户个人资料的实体,此表格不可编辑,之前已填充。但是与表的关系应该是。
@Entity
@Table(name="USER_PROFILE")
public class UserProfile implements Serializable{
/**
*
*/
private static final long serialVersionUID = 3901763913690001763L;
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
//@Column(name = "ID_USER_PROFILE", nullable = false)
private Integer id_user_profile;
//TODO HACER NULLABLE LOS ATRIBUTOS
@Column(name="TIPO", length=15, unique=true, nullable=false)
private String tipo = UserProfileType.CLIENTE.getUserProfileType();
public UserProfile (Integer id, String tipo){
this.id_user_profile = id;
this.tipo = tipo;
}
public UserProfile (){
super();
}
public String getTipo() {
return tipo;
}
public void setTipo(String type) {
this.tipo = type;
}
public Integer getId_user_profile() {
return id_user_profile;
}
public void setId_user_profile(Integer id_user_profile) {
this.id_user_profile = id_user_profile;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id_user_profile == null) ? 0 : id_user_profile.hashCode());
result = prime * result + ((tipo == null) ? 0 : tipo.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof UserProfile))
return false;
UserProfile other = (UserProfile) obj;
if (id_user_profile == null) {
if (other.id_user_profile != null)
return false;
} else if (!id_user_profile.equals(other.id_user_profile))
return false;
if (tipo == null) {
if (other.tipo != null)
return false;
} else if (!tipo.equals(other.tipo))
return false;
return true;
}
@Override
public String toString() {
return "UserProfile [id=" + id_user_profile + ", type=" + tipo + "]";
}
}
表格的创作句子。
CREATE TABLE PERSONA (
ID_PERSONA bigint NOT NULL auto_increment,
NOMBRE VARCHAR(50) not null,
APELLIDOS VARCHAR(50) not null,
FECHA_NACIMIENTO VARCHAR(50) not null,
MAIL VARCHAR(50) not null,
USUARIO VARCHAR(50) not null,
PASSWORD VARCHAR(256) not null,
TELEFONO VARCHAR(50) not null,
SEXO VARCHAR(50) not null,
LOCALIDAD VARCHAR(20) NOT NULL,
IS_CLIENTE bool not null,
ID_CLIENTE bigint REFERENCES CLIENTE(ID_CLIENTE) ON DELETE CASCADE,
PRIMARY KEY (ID_PERSONA),
UNIQUE (USUARIO)
);
create table USER_PROFILE(
ID_USER_PROFILE BIGINT NOT NULL auto_increment,
TIPO VARCHAR(30) NOT NULL,
PRIMARY KEY (ID_USER_PROFILE),
UNIQUE (TIPO)
);
/* JOIN TABLE for MANY-TO-MANY relationship*/
CREATE TABLE PERSONA_USER_PROFILE (
ID_PERSONA BIGINT NOT NULL,
ID_USER_PROFILE BIGINT NOT NULL,
PRIMARY KEY (ID_PERSONA, ID_USER_PROFILE),
CONSTRAINT FK_APP_USER FOREIGN KEY (ID_PERSONA) REFERENCES PERSONA (ID_PERSONA),
CONSTRAINT FK_USER_PROFILE FOREIGN KEY (ID_USER_PROFILE) REFERENCES USER_PROFILE (ID_USER_PROFILE)
);
如果我注释掉声明cascadetype.ALL的行以进行多对多的通奸,我会得到这个堆栈跟踪。
Hibernate:
select
this_.id_user_profile as id_user_1_5_0_,
this_.TIPO as TIPO2_5_0_
from
USER_PROFILE this_
order by
this_.TIPO asc
Hibernate:
insert
into
CLIENTE
(ALIAS, DESCRIPCION, EDAD_MAX, EDAD_MIN, ORIENTACION_SEXUAL, VALORACION)
values
(?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
PERSONA
(APELLIDOS, ID_CLIENTE, IS_CLIENTE, FECHA_NACIMIENTO, LOCALIDAD, MAIL, NOMBRE, PASSWORD, SEXO, TELEFONO, USUARIO)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
PERSONA_USER_PROFILE
(ID_PERSONA, ID_USER_PROFILE)
values
(?, ?)
sep 18, 2016 9:13:54 PM org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: El Servlet.service() para el servlet [dispatcher] en el contexto con ruta [/application] lanzó la excepción [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: com.aphroditesocial.web.model.UserProfile; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.aphroditesocial.web.model.UserProfile] con causa raíz
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.aphroditesocial.web.model.UserProfile
at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:294)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:537)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:165)
at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:899)
at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1308)
at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:67)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465)
答案 0 :(得分:0)
在PersonalData类中更改以下内容:
@ManyToMany(
fetch = FetchType.LAZY
, cascade = CascadeType.ALL
)
为:
@ManyToMany(
fetch = FetchType.LAZY
)
希望这有帮助。