Карта однонаправленных отношений один-к-одному в Hibernate 5 - PullRequest
0 голосов
/ 04 июня 2018

У меня очень простой вопрос, почему hibernate не переносит первичный ключ сущности Account в сущность User , когда я сохраняю сущность Account как, например, если это делает @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. получить идентификатор от генератора, установить его на учетной записи
  2. сохранить учетную запись
  3. установитьИдентификатор учетной записи пользователя
  4. постоянный пользователь

Почему вышеописанное не происходит?Есть ли способ, как это работает, как я ожидаю?

Однако, если я вручную назначу идентификатор пользователя, это работает без проблем:

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 голосов
/ 06 июня 2018

Спецификация 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;
}

Обсуждаются производные идентификаторы (с примерами)в спецификации JPA 2.2 в разделе 2.4.1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...