uno a muchos hibernar

Hola, estoy tratando de hacer una inserción de uno a muchos, pero tengo problemas. Tengo dos mesas:

CREATE TABLE users_app (
  user_id int UNSIGNED NOT NULL AUTO_INCREMENT,
  user_number varchar(45) NOT NULL default '0',
  user_password varchar(45) NOT NULL default '0',
  os int(1) unsigned NOT NULL,
  token varchar(500) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;

CREATE TABLE user_app_devices(  
    id int AUTO_INCREMENT PRIMARY KEY,  
    user_id int UNSIGNED NOT NULL,
    device_name varchar(45) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users_app (user_id)  
)ENGINE=InnoDB CHARSET=utf8;

Mis clases:

@Entity
@Table(name="user_app_devices")
public class UserAppDevice implements Serializable {
private static final long serialVersionUID = 1L;

@Id
private int id;

@Column(name="device_name")
private String deviceName;

//bi-directional many-to-one association to UsersApp
@ManyToOne
@JoinColumn(name="user_id")
private UsersApp usersApp;

public UserAppDevice() {
}

public int getId() {
    return this.id;
}

public void setId(int id) {
    this.id = id;
}

public String getDeviceName() {
    return this.deviceName;
}

public void setDeviceName(String deviceName) {
    this.deviceName = deviceName;
}

public UsersApp getUsersApp() {
    return this.usersApp;
}

public void setUsersApp(UsersApp usersApp) {
    this.usersApp = usersApp;
}

}

@Entity
@Table(name="users_app")
public class UsersApp implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@Column(name="user_id")
private int userId;

private int os;

private String token;

@Column(name="user_number")
private String userNumber;

@Column(name="user_password")
private String userPassword;

//bi-directional many-to-one association to UserAppDevice
@OneToMany(mappedBy="usersApp")
private List<UserAppDevice> userAppDevices;

public UsersApp() {
}

public int getUserId() {
    return this.userId;
}

public void setUserId(int userId) {
    this.userId = userId;
}

public int getOs() {
    return this.os;
}

public void setOs(int os) {
    this.os = os;
}

public String getToken() {
    return this.token;
}

public void setToken(String token) {
    this.token = token;
}

public String getUserNumber() {
    return this.userNumber;
}

public void setUserNumber(String userNumber) {
    this.userNumber = userNumber;
}

public String getUserPassword() {
    return this.userPassword;
}

public void setUserPassword(String userPassword) {
    this.userPassword = userPassword;
}

public List<UserAppDevice> getUserAppDevices() {
    return this.userAppDevices;
}

public void setUserAppDevices(List<UserAppDevice> userAppDevices) {
    this.userAppDevices = userAppDevices;
}

public UsersApp(int os, String token, String userNumber, String userPassword) {
    this.os = os;
    this.token = token;
    this.userNumber = userNumber;
    this.userPassword = userPassword;
}

Quiero agregar un nuevo usuario con dispositivo

Intento este código:

    Session session = (Session) em.getDelegate();
    session.beginTransaction();

    UsersApp user = new UsersApp(os, token, userNumber, userPassword);

    session.save(user);

    UserAppDevice ud = new UserAppDevice();

    ud.setUsersApp(user);
    ud.setDeviceName(device);

    session.save(ud);

    session.getTransaction().commit();

pero me enfrento a una excepción:

13:16:48,516 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--0.0.0.0-8080-3) SQL Error: 1452, SQLState: 23000
13:16:48,517 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http--0.0.0.0-8080-3) Cannot add or update a child row: a foreign key constraint fails (`application`.`user_a
pp_devices`, CONSTRAINT `user_app_devices_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_app` (`user_id`))
13:16:48,520 ERROR [org.jboss.as.ejb3.tx.CMTTxInterceptor] (http--0.0.0.0-8080-3) javax.ejb.EJBTransactionRolledbackException: Cannot add or update a child row: a foreign key const
raint fails (`application`.`user_app_devices`, CONSTRAINT `user_app_devices_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_app` (`user_id`))
13:16:48,524 ERROR [org.jboss.ejb3.invocation] (http--0.0.0.0-8080-3) JBAS014134: EJB Invocation failed on component DeviceRegisterDAOImpl for method public abstract void com.break
id.ejb.model.DeviceRegisterDAO.add(int,java.lang.String,java.lang.String,java.lang.String,java.lang.String): javax.ejb.EJBTransactionRolledbackException: Cannot add or update a chi
ld row: a foreign key constraint fails (`application`.`user_app_devices`, CONSTRAINT `user_app_devices_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users_app` (`user_id`))
        at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:139) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
        at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:204) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
        at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:306) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
        at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:190) [jboss-as-ejb3-7.1.1.Final.jar:7.1.1.Final]
        at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.1.Final.jar:1.1.1.Final]
        at org.jboss.as.ejb3.remote.EJBRemoteTransactionPropagatingInterceptor.processInvocation(EJBRemoteTransactionPropagatingInterceptor.java:80) [jboss-as-ejb3-7.1.1.Final.jar:
7.1.1.Final]

Qué me estoy perdiendo ?

preguntado el 31 de julio de 12 a las 11:07

3 Respuestas

No le ha dicho a Hibernate que la ID de UserApp fue generada automáticamente por la base de datos:

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name="user_id")
private int userId;

(y haz lo mismo con la otra entidad)

Respondido 31 Jul 12, 11:07

Dado que está utilizando bidireccional, cambie su código de cliente como se muestra a continuación.

Session session = (Session) em.getDelegate();
session.beginTransaction();
UserAppDevice ud = new UserAppDevice();
ud.setDeviceName(device);
UsersApp user = new UsersApp(os, token, userNumber, userPassword);
user.setUserAppDevices(new ArrayList<UserAppDevice>())
user.getUserAppDevices().add(ud);
session.save(user);
session.getTransaction().commit();

Respondido 31 Jul 12, 11:07

Esto no funcionó, solo el usuario agregó a la base de datos, el dispositivo no funcionó: miguel biniashvili

Como mencionó JB Nizet, te estás perdiendo la estrategia generada automáticamente.

Una alternativa sería utilizar UUID como tu id columna y cree los valores usted mismo con

@Id
private UUID id = UUID.randomUUID();

Además, no olvide configurar equals/hashCode utilizar el id campo como se discutió hasta la muerte en El dilema hashCode () / equals () de JPA

Por cierto, ¿por qué estás usando Session (específico de hibernación) en lugar de apegarse a la API de JPA?

contestado el 23 de mayo de 17 a las 11:05

El OP tiene un atributo mappedBy, y es obligatorio en cada asociación bidireccional, ya sea que se use una tabla de combinación o una columna de combinación. Con respecto a equals/hashCode: no son obligatorios en absoluto, e Hibernate recomienda NO usar la ID. - JB Nizet

llegaste demasiado tarde :-PI en realidad vio eso y actualizó mi comentario hace 7 minutos. No obtengo barras de desplazamiento en fragmentos de código y originalmente no vi el segundo class definición. Sé que Hibernate recomendó una clave comercial, pero ese argumento es anticuado: la convención moderna es usar id Y genere las claves usted mismo en la construcción. yo suelo UUID porque evita tener que usar sistemas extraños para garantizar la unicidad en la base de datos. - fommil

Eso es solo moderno en tu casa. Un UUID es menos eficiente que un número para PK, y las secuencias o el incremento automático son mucho más fáciles de usar que los UUID. - JB Nizet

El uso de UUID es mi propio giro, y tiene razón sobre el rendimiento, pero nunca me afectó, aunque estoy bastante seguro de que la gente de Hibernate ahora está de acuerdo en que las claves principales se pueden usar si la clave se genera durante la construcción. Prefiero lanzar una excepción en hashCode if id no está configurado que pasar por la molestia de obtener un Long para usar en la construcción. - fommil

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.