2

Hi I am trying to do one to many insert but I am having problems. I have two tables:

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;

My classes:

@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;
}

I want to add new user with device

I try this code:

    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();

but I am facing exception:

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]

What am I missing ?

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
Michael Biniashvili
  • 500
  • 1
  • 12
  • 24

3 Answers3

1

You haven't told Hibernate that the ID of UserApp was generated automatically by the database:

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

(and do the same for the other entity)

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

Since your are using bidirectional, change your client code as below.

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();
NPKR
  • 5,368
  • 4
  • 31
  • 48
0

As mentioned by JB Nizet, you're missing the autogenerated strategy.

An alternative would be to use UUID as your id column and create the values yourself with

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

Also, don't forget to set equals/hashCode to use the id field as discussed to death in The JPA hashCode() / equals() dilemma

Incidentally, why are you using Session (hibernate specific) instead of sticking to JPA's API?

Community
  • 1
  • 1
fommil
  • 5,757
  • 8
  • 41
  • 81
  • The OP has a mappedBy attribute, and it's mandatory in every bidirectional association, whether a join table is used or a join column is used. Regarding equals/hashCode: they're not mandatory at all, and Hibernate recommends NOT using the ID. – JB Nizet Jul 31 '12 at 10:51
  • you're too late :-P I actually spotted that and updated my comment 7 mins ago. I don't get scrollbars on code snippets and I didn't originally see the second `class` definition. I know Hibernate recommended a business key, but that argument is old hat - the modern convention is to use `id` AND generate the keys yourself on construction. I use `UUID` because it avoids having to use bizarre systems to ensure uniqueness in the DB. – fommil Jul 31 '12 at 10:56
  • That's only modern at your place. A UUID is less efficient than a number for PKs, and sequences or auto_increment are much easier to use than UUIDs. – JB Nizet Jul 31 '12 at 11:16
  • The use of `UUID` is my own twist on it - and you're right about performance, but it's never affected me - although I am pretty sure the Hibernate folk are now in agreement that primary keys can be used if the key is generated during construction. I'd rather just throw an exception in `hashCode` if `id` is not set than go through the hassle of getting an appropriate `Long` to use at construction. – fommil Jul 31 '12 at 11:18