title: Correct Way to Implement One to One foreign keys Using hibernate and JPA
body: <p>So I have 2 objects, Users and LastFm accounts. Now User's may not have a LastFm account but every LastFm account will be mapped to exactly one user. Now that you know a little about the problem space, here's the issue: I'm having exceptions occur whenever I save my LastFm accounts. Here's the exception:</p>
  
  <pre><code>Hibernate: insert into LAST_FM_ACCOUNT (LAST_FM_PASSWORD, LAST_FM_USERNAME, USER_ID) values (?, ?, ?)
  Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`mobsterdb`.`LAST_FM_ACCOUNT`, CONSTRAINT `USER_ID_FK` FOREIGN KEY (`USER_ID`) REFERENCES `MOBSTER_USER` (`USER_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION)
      at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:74)
      at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
      at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
      at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
      at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
      at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
      at $Proxy17.executeUpdate(Unknown Source)
      at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:96)
      at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
      at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2767)
      at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3278)
      at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
      at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
      at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:203)
      at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:183)
      at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:167)
      at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:320)
      at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:287)
      at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
      at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:126)
      at org.hibernate.ejb.event.EJB3SaveEventListener.saveWithGeneratedId(EJB3SaveEventListener.java:71)
      at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:204)
      at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
      at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:189)
      at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
      at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
      at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:757)
      at org.hibernate.internal.SessionImpl.save(SessionImpl.java:749)
      at org.hibernate.internal.SessionImpl.save(SessionImpl.java:745)
      at mobster.persistence.dao.generic.MobsterBaseHibernateDAO.create(MobsterBaseHibernateDAO.java:22)
      at cc.main(cc.java:35)
  Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`mobsterdb`.`LAST_FM_ACCOUNT`, CONSTRAINT `USER_ID_FK` FOREIGN KEY (`USER_ID`) REFERENCES `MOBSTER_USER` (`USER_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION)
      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)
      at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
      at com.mysql.jdbc.Util.getInstance(Util.java:386)
      at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1040)
      at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074)
      at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006)
      at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468)
      at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629)
      at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2719)
      at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
      at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2450)
      at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2371)
      at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2355)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
      at java.lang.reflect.Method.invoke(Unknown Source)
      at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
      ... 26 more
  </code></pre>
  
  <p>Here are the two entity classes:</p>
  
  <pre><code>@Entity
  @Table(name = "LAST_FM_ACCOUNT")
  public final class LastFmAccount implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Id
  @GeneratedValue(generator = "system-id")
  @GenericGenerator(name = "system-id", strategy = "identity")
  @Column(name = "LAST_FM_ACCOUNT_ID", unique = true)
  private int id;
  
  @NotNull
  @Column(name = "LAST_FM_USERNAME")
  @Type(type = "encryptedString")
  private String lastFmUserName;
  
  @NotNull
  @Column(name = "LAST_FM_PASSWORD")
  @Type(type = "encryptedString")
  private String lastFmPassword;
  
  @OneToOne
  @JoinColumn(name = "USER_ID")
  private MobsterUser user;
  
  public LastFmAccount() {
      /* null op */
  }
  
  public LastFmAccount(String lastFmUserName, String lastFmPassword,
          MobsterUser user) {
      super();
      this.lastFmUserName = lastFmUserName;
      this.lastFmPassword = lastFmPassword;
      this.user = user;
  }
  
  public int getId() {
      return id;
  }
  
  public void setId(int id) {
      this.id = id;
  }
  
  public String getLastFmUserName() {
      return lastFmUserName;
  }
  
  public void setLastFmUserName(String lastFmUserName) {
      this.lastFmUserName = lastFmUserName;
  }
  
  public String getLastFmPassword() {
      return lastFmPassword;
  }
  
  public void setLastFmPassword(String lastFmPassword) {
      this.lastFmPassword = lastFmPassword;
  }
  
  public MobsterUser getUser() {
      return user;
  }
  
  public void setUser(MobsterUser user) {
      this.user = user;
  }
  
  @Override
  public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + id;
      result = prime * result
              + ((lastFmPassword == null) ? 0 : lastFmPassword.hashCode());
      result = prime * result
              + ((lastFmUserName == null) ? 0 : lastFmUserName.hashCode());
      result = prime * result + ((user == null) ? 0 : user.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;
      LastFmAccount other = (LastFmAccount) obj;
      if (id != other.id)
          return false;
      if (lastFmPassword == null) {
          if (other.lastFmPassword != null)
              return false;
      } else if (!lastFmPassword.equals(other.lastFmPassword))
          return false;
      if (lastFmUserName == null) {
          if (other.lastFmUserName != null)
              return false;
      } else if (!lastFmUserName.equals(other.lastFmUserName))
          return false;
      if (user == null) {
          if (other.user != null)
              return false;
      } else if (!user.equals(other.user))
          return false;
      return true;
  }
  
  @Override
  public String toString() {
      return "LastFmAccount [id=" + id + ", lastFmUserName=" + lastFmUserName
              + ", lastFmPassword=" + lastFmPassword + ", user=" + user + "]";
  } 
  }
  //New Table
  @Entity @Table(name = "MOBSTER_USER")
  public final class MobsterUser implements Serializable {
  private static final long serialVersionUID = 1L;
  private String userId, email, password, firstName, lastName;
  private char gender;
  private Date birthday;
  
  public MobsterUser() {
  
  }
  
  public MobsterUser(String email, String password,
          String firstName, String lastName, char gender, Date birthday) {
      this.email = email;
      this.password = password;
      this.firstName = firstName;
      this.lastName = lastName;
      this.gender = gender;
      this.birthday = birthday;
  }
  
  @Id
  @GeneratedValue(generator="system-uuid")
  @GenericGenerator(name="system-uuid", strategy = "uuid")
  @Column(name = "USER_ID", unique = true)
  public String getUserId() {
      return userId;
  }
  
  public void setUserId(String userId) {
      this.userId = userId;
  }
  
  @Column(name = "EMAIL", unique = true)
  @NotNull
  public String getEmail() {
      return email;
  }
  
  public void setEmail(String email) {
      this.email = email;
  }
  
  @Column(name = "PASSWORD")
  @NotNull
  @Type(type="encryptedString")
  public String getPassword() {
      return password;
  }
  
  public void setPassword(String password) {
      this.password = password;
  }
  
  @Column(name = "FIRST_NAME")    
  @NotNull
  public String getFirstName() {
      return firstName;
  }
  
  public void setFirstName(String firstName) {
      this.firstName = firstName;
  }
  
  @Column(name = "LAST_NAME")
  @NotNull
  public String getLastName() {
      return lastName;
  }
  
  public void setLastName(String lastName) {
      this.lastName = lastName;
  }
  
  @Column(name = "GENDER")
  @NotNull
  public char getGender() {
      return gender;
  }
  
  public void setGender(char gender) {
      this.gender = gender;
  }
  
  @Column(name = "BIRTHDATE")
  @Temporal(TemporalType.DATE)
  public Date getBirthday() {
      return birthday;
  }
  
  public void setBirthday(Date birthday) {
      this.birthday = birthday;
  }
  
  @Override
  public String toString() {
      return "MobsterUser [userId=" + userId + ", email=" + email
              + ", password=" + password + ", firstName=" + firstName
              + ", lastName=" + lastName + ", gender=" + gender
              + ", birthday=" + birthday + "]";
  }
  
  }
  </code></pre>
  
  <p>Now I know there are several post regarding essentially the same issue, but does anyone see what I'm doing wrong here?</p>