在Hibernate中映射单向一对一关系5

时间:2018-06-04 20:28:44

标签: hibernate jpa

我的问题非常简单,当我坚持帐户时,为什么hibernate不会自动将帐户实体的主键带到用户实体实体,例如,如果它是@mapsId?

如果我们记住这个映射:

@Entity
@Table(name="account")
@Getter
@Setter
public class Account implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="id")
    @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    private int accountId;

    @Column(name="email")
    private String email;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn(name="id", referencedColumnName="pk_account$user")
    private User user;

}

@Entity
@Table(name="user")
@Getter
@Setter
public class User implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="pk_account$user")
    private int userId;

    @Column(name="identification_number")
    private String identificationNumber;

}

然后我这样做:

public static void main( String[] args )
    {
        SessionFactory sessionFactory;
        Configuration configuration= new Configuration();
        configuration.configure();
        sessionFactory=configuration.buildSessionFactory();
        Session session= sessionFactory.openSession();
        session.beginTransaction();
        Account account= new Account();
        account.setEmail("new@gmail.com");

        User user= new User();
        user.setIdentificationNumber("11462727272");
        account.setUser(user);

        session.persist(account);
        session.getTransaction().commit();

    }

我有这个错误:

Hibernate: insert into account (email) values (?)
Hibernate: insert into user (identification_number, pk_account$user) values (?, ?)
    Jun 04, 2018 5:41:16 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
    WARN: SQL Error: 1452, SQLState: 23000
    Jun 04, 2018 5:41:16 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
    ERROR: Cannot add or update a child row: a foreign key constraint fails (`prueba`.`user`, CONSTRAINT `fk_user_account` FOREIGN KEY (`pk_account$user`) REFERENCES `account` (`id`))
    Jun 04, 2018 5:41:16 PM org.hibernate.internal.ExceptionMapperStandardImpl mapManagedFlushFailure
    ERROR: HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
    Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:164)
        at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1460)
        at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
        at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3278)
        at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2474)
        at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
        at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98)
        at com.espiritware.pruebaOneToOne.App.main(App.java:32)
    Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
        at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
        at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3136)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3651)
        at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:90)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
        at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
        at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
        at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
        at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
        ... 9 more
    Caused by: java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`prueba`.`user`, CONSTRAINT `fk_user_account` FOREIGN KEY (`pk_account$user`) REFERENCES `account` (`id`))
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:115)
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)
        at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
        at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:960)
        at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1116)
        at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1066)
        at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1396)
        at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1051)
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
        ... 17 more

我期待以下内容:

  1. 从发电机获取ID,将其设置在帐户
  2. 坚持帐户
  3. 在用户
  4. 上设置帐户ID
  5. 坚持用户
  6. 为什么上述情况不会发生?这有什么方法可以像我期望的那样工作吗?

    但是,如果我手动将id分配给用户,则可以正常工作:

    public static void main( String[] args )
    {
        SessionFactory sessionFactory;
        Configuration configuration= new Configuration();
        configuration.configure();
        sessionFactory=configuration.buildSessionFactory();
        Session session= sessionFactory.openSession();
        session.beginTransaction();
        Account account= new Account();
        account.setEmail("new@gmail.com");
    
        session.persist(account);
    
        User user= new User();
        user.setUserId(account.getAccountId());
        user.setIdentificationNumber("11462727272");
        account.setUser(user);
    
        session.persist(account);
        session.getTransaction().commit();
    
    }
    

    如果有人能给你解释,我真的很感激。我想这样做而不需要手动分配,保持单向关系

1 个答案:

答案 0 :(得分:1)

JPA规范表明您不应再使用@PrimaryKeyJoinColumn进行@OneToOne映射。由于User主键由Account确定,您可以尝试双向一对一并使用“派生身份”:

@Entity
@Table(name="account")
@Getter
@Setter
public class Account implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="id")
    @GeneratedValue(strategy= GenerationType.AUTO, generator="native")
    @GenericGenerator(name = "native", strategy = "native")
    private int accountId;

    @Column(name="email")
    private String email;

    @OneToOne(cascade = CascadeType.ALL, mappedBy="account")
    private User user;
}

@Entity
@Table(name="user")
@Getter
@Setter
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="pk_account$user")
    private int userId;

    @OneToOne
    @MapsId
    private Account account;

    @Column(name="identification_number")
    private String identificationNumber;
}

在第2.4.1节的JPA 2.2 spec中讨论派生身份(带示例)。

相关问题