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");
  }

}
失败是
at
assertThat(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");
      }
}