1

我有 2 个类似于以下内容的 JPA 实体:

@Entity
class Customer {
   @Id
   @GeneratedValue
   Long id

   @OneToOne(cascade = CascadeType.ALL)
   @PrimaryKeyJoinColumn
   CustomerInformation customerInformation
}


@Entity
class CustomerInformation {
   @Id
   @OneToOne
   @JoinColumn(name = "id")
   Customer customer

   String firstName
   String lastName
}

我正在使用 spring-data-jpa 来生成我的 DAO 层。在这里,虽然它不是很有趣:

public interface CustomerRepository extends CrudRepository<Customer, Long> {
}

我在 spring 上下文中调用它并使用 @Transactional 注释来告诉 JPA 提供程序何时将事务提交到数据库。为了测试,我使用@PersistenceContext 抓取实体管理器并手动刷新它以结束事务。由于我们应用程序的性质,数据库中可能存在一个客户,但没有与之关联的 customerInformation 对象。如果我在同一个事务中创建一个新客户和一个 customerInformation 对象,事情就会像我预期的那样工作。例如,这有效:

@Transactional
public void createNewCustomer() {
   Customer cust = new Customer();
   CustomerInformation custInf = new CustomerInformation;
   custInf.setCustomer(cust);
   custInf.setFirstName("asdf");
   custInf.setLastName("hjkl");

   cust.setCustomerInformation(custInf);

   customerRepository.save(cust);
}

但是,如果我想更新现有客户,我会遇到一个问题,即它尝试插入具有空 id 的 CustomerInformation 对象。例如,这惨遭失败:

@Transactional
public void updateExistingCustomer(Long userId) {

   Customer foundCustomer = customerRepository.findOne(userId);

   if (foundCustomer.getCustomerInformation() == null) {
      CustomerInformation custInf = new CustomerInformation();
      custInf.setCustomer(foundCustomer);
      custInf.setFirstName("asdf");
      custInf.setLastName("hjkl");

      cust.setCustomerInformation(custInf);

      customerRepository.save(foundCustomer);
   }
}

这失败并显示错误消息:

Hibernate: insert into CustomerInformation (firstName, lastName, id) values (?, ?, ?)
Feb 1, 2013 7:40:12 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 20000, SQLState: 23502
Feb 1, 2013 7:40:12 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Column 'ID'  cannot accept a NULL value.

我是不是误会了什么?任何帮助表示赞赏。

提前致谢!

4

2 回答 2

1

您也应该将Id字段标记为生成的值,因此 hibernate 会为它提供一些值:

@Entity
class Customer {
   @Id
   @GeneratedValue // !!!
   Long id

...

@Entity
class CustomerInformation {
   @Id
   @GeneratedValue // !!!
   @OneToOne
   @JoinColumn(name = "id")
   Customer customer

...
于 2013-02-02T01:12:22.230 回答
0

我将实体修改为如下所示:

@Entity
class CustomerInformation {

    @Id
    Long id

    @MapsId
    @OneToOne
    @JoinColumn(name = "id")
    Customer customer

    String firstName
    String lastName
}

一切正常。据我所知,这两个版本CustomerInformation都会产生相同的 SQL,除了第二个版本模拟实际的 id,我不一定需要它。我将在另一个问题中对此进行扩展,但上面的代码解决了我的问题。

于 2013-02-05T23:03:15.413 回答