Java 运行spring boot JPA测试时,数据库中没有保留值
我正在寻找在Java 运行spring boot JPA测试时,数据库中没有保留值,java,hibernate,jpa,spring-data-jpa,Java,Hibernate,Jpa,Spring Data Jpa,我正在寻找在spring数据jpa中映射列默认值的解决方案,这使我获得了@ColumnDefault注释的文档;我想尝试一下。因此,我更新了一个需要默认值的实体(今天,这是通过schema.sql处理的,在这里我们定义了额外的列行为),如下所示: 这是失败的测试 @Slf4j @RunWith(SpringRunner.class) @DataJpaTest(showSql = false) @ContextConfiguration(classes = { DataApiJpaConfigur
spring数据jpa
中映射列默认值的解决方案,这使我获得了@ColumnDefault
注释的文档;我想尝试一下。因此,我更新了一个需要默认值的实体(今天,这是通过schema.sql处理的,在这里我们定义了额外的列行为),如下所示:
这是失败的测试
@Slf4j
@RunWith(SpringRunner.class)
@DataJpaTest(showSql = false)
@ContextConfiguration(classes = { DataApiJpaConfiguration.class })
@TestPropertySource(locations = {"classpath:application-it.properties","classpath:application-test.properties"})
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class CustomerRepositoryIntegrationTest {
@Autowired
private CustomerRepository customerRepository;
@Test
public void testPrePersistAddsMandatoryFields() {
Customer bhau = new Customer();
bhau.setName("Bhau & Sons Pvt. Ltd.");
bhau.setDomain(RandomStringUtils.randomAlphanumeric(8));
bhau = customerRepository.saveAndFlush(bhau);
Customer badaBhau = customerRepository.findById(bhau.getId()).get();
assertThat(badaBhau.getTds().doubleValue()).isEqualTo(0.10);
assertThat(badaBhau.getInvoicePrefix()).isEqualTo("INV");
assertThat(badaBhau.getCurrency()).isEqualTo("INR");
}
}
失败是atassertThat(badaBhau.getts().doubleValue()).isEqualTo(0.10)的NullPointerException
当我在debug上运行时,我注意到当从数据库查询时,badaBhau
确实没有设置默认值。然后,当该行持续出现时,我在该行后暂停bhau
;浏览已配置的测试数据库并注意到bhau
实体最初甚至没有保存到数据库中
我还使用Postgesql-Dev-DB运行了这个应用程序,试图点击API url以使用JSON数据保存客户
{
"name":"Minty and Sons Pvt. Ltd.",
"pan": "AASONAL123",
"domain": "xy123456"
}
此调用成功地创建了课程记录,其中默认值分别为INR
,INV
,0.10
,invoice\u prefix
和tds
因此,虽然我理解并喜欢@ColumnDefault
如何为我解决默认值问题;由于Hibernate的一级缓存,bhau
和badaBhau
将是同一个实例,因此我完全不知道测试失败的原因(或者我做错了什么)。以下操作不会触发数据库查找:相反,将从一级缓存检索具有指定ID的客户。您可以通过启用SQL日志来验证这一点
Customer-badaBhau=customerRepository.findById(bhau.getId())//无数据库查找
获取该值可以通过清除持久性上下文或刷新持久性实例来强制数据库查找
public class MyTestClass {
@PersistenceContext
private EntityManager em;
@Test
public void testDefaultFieldsArePopulated() {
Customer bhau = new Customer();
bhau.setName("Bhau & Sons Pvt. Ltd.");
bhau.setDomain(RandomStringUtils.randomAlphanumeric(8));
bhau = customerRepository.saveAndFlush(bhau);
em.clear(); //db lookup will now happen
Customer badaBhau = customerRepository.findById(bhau.getId());
assertThat(badaBhau.getTds().doubleValue()).isEqualTo(0.10);
assertThat(badaBhau.getInvoicePrefix()).isEqualTo("INV");
assertThat(badaBhau.getCurrency()).isEqualTo("INR");
}
}
Crizzis在他的回答中也提出了一个有效点,当测试通过时,Postgres似乎正在用列的默认值替换null。由于您可能无法跨不同的数据库引擎依赖于此,因此您还可以考虑在实体上使用Hibernates@DynamicInsert
注释,该注释将创建一个只设置非空字段的insert语句
对于插入,此实体是否应在以下位置使用动态sql生成
在准备好的sql语句中仅引用非空列
由于Hibernate的一级缓存,bhau
和badaBhau
将是同一个实例,即。以下操作不会触发数据库查找:相反,将从一级缓存检索具有指定ID的客户。您可以通过启用SQL日志来验证这一点
Customer-badaBhau=customerRepository.findById(bhau.getId())//无数据库查找
获取该值可以通过清除持久性上下文或刷新持久性实例来强制数据库查找
public class MyTestClass {
@PersistenceContext
private EntityManager em;
@Test
public void testDefaultFieldsArePopulated() {
Customer bhau = new Customer();
bhau.setName("Bhau & Sons Pvt. Ltd.");
bhau.setDomain(RandomStringUtils.randomAlphanumeric(8));
bhau = customerRepository.saveAndFlush(bhau);
em.clear(); //db lookup will now happen
Customer badaBhau = customerRepository.findById(bhau.getId());
assertThat(badaBhau.getTds().doubleValue()).isEqualTo(0.10);
assertThat(badaBhau.getInvoicePrefix()).isEqualTo("INV");
assertThat(badaBhau.getCurrency()).isEqualTo("INR");
}
}
Crizzis在他的回答中也提出了一个有效点,当测试通过时,Postgres似乎正在用列的默认值替换null。由于您可能无法跨不同的数据库引擎依赖于此,因此您还可以考虑在实体上使用Hibernates@DynamicInsert
注释,该注释将创建一个只设置非空字段的insert语句
对于插入,此实体是否应在以下位置使用动态sql生成
在准备好的sql语句中仅引用非空列
我的部分答案是@AlanHay已经提到的
即使你听从他的建议,我仍然认为你的考试会失败。@ColumnDefault
的目的是在执行DLL时,将指定的默认值与列定义一起使用。默认值的意思是:“INSERT
语句中未指定列的值时,请使用以下值”
问题是,您正在为列指定一个值,因为您的列并没有使用insertable=false
从INSERT
语句中排除。即使您没有为属性设置值,Hibernate也会发送一个显式的NULL
。您的方法可能适用于currency
和indexPrefix
,因为您将它们标记为nullable=false
(这是特定于数据库的,您必须查阅文档以了解Postgres如何处理这种情况)。我非常怀疑它是否适用于tds
列,因为在这种情况下NULL
是一个有效值 我的部分答案是@AlanHay已经提到的
即使你听从他的建议,我仍然认为你的考试会失败。@ColumnDefault
的目的是在执行DLL时,将指定的默认值与列定义一起使用。默认值的意思是:“INSERT
语句中未指定列的值时,请使用以下值”
问题是,您正在为列指定一个值,因为您的列并没有使用insertable=false
从INSERT
语句中排除。即使您没有为属性设置值,Hibernate也会发送一个显式的NULL
。您的方法可能适用于currency
和indexPrefix
,因为您将它们标记为nullable=false
(这是特定于数据库的,您必须查阅文档以了解Postgres如何处理这种情况)。我非常怀疑它是否适用于tds
列,因为在这种情况下NULL
是一个有效值 如何注入customerRepository
bean?更新了测试用例代码,我正在使用springbootstarter测试
public class MyTestClass {
@PersistenceContext
private EntityManager em;
@Test
public void testDefaultFieldsArePopulated() {
Customer bhau = new Customer();
bhau.setName("Bhau & Sons Pvt. Ltd.");
bhau.setDomain(RandomStringUtils.randomAlphanumeric(8));
bhau = customerRepository.saveAndFlush(bhau);
em.clear(); //db lookup will now happen
Customer badaBhau = customerRepository.findById(bhau.getId());
assertThat(badaBhau.getTds().doubleValue()).isEqualTo(0.10);
assertThat(badaBhau.getInvoicePrefix()).isEqualTo("INV");
assertThat(badaBhau.getCurrency()).isEqualTo("INR");
}
}