我有两个类似于以下内容的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.
我误解了什么吗?任何帮助表示赞赏。
提前致谢!
答案 0 :(得分:1)
你应该将Id
字段标记为生成的值,因此hibernate会为它提供一些值:
@Entity
class Customer {
@Id
@GeneratedValue // !!!
Long id
...
@Entity
class CustomerInformation {
@Id
@GeneratedValue // !!!
@OneToOne
@JoinColumn(name = "id")
Customer customer
...
答案 1 :(得分:0)
我将实体修改为如下所示:
@Entity
class CustomerInformation {
@Id
Long id
@MapsId
@OneToOne
@JoinColumn(name = "id")
Customer customer
String firstName
String lastName
}
一切顺利。据我所知,CustomerInformation
的两个版本都会产生相同的SQL,除了第二个版本模拟实际的id,我不一定需要。我将在另一个问题中扩展它,但上面的代码解决了我的问题。