Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA版本使用Orika进行类映射的奇怪行为。子版本将递增,但不应';T_Java_Hibernate_Jpa_Spring Data_Orika - Fatal编程技术网

Java JPA版本使用Orika进行类映射的奇怪行为。子版本将递增,但不应';T

Java JPA版本使用Orika进行类映射的奇怪行为。子版本将递增,但不应';T,java,hibernate,jpa,spring-data,orika,Java,Hibernate,Jpa,Spring Data,Orika,在我的数据库模型中,每个实体都有版本字段。 我有三个简单的实体(客户、债务、付款)和@OneToMany realtions。客户有很多债务。债务有很多偿还。 我还使用Orika进行类映射(dto->entity和entity->dto) 我有两个测试用例: 我已经完全满足并坚持客户需求。然后我换一个 几乎每次更改后,客户只需保存一个属性。在测试用例的末尾 客户实体的版本是递增的。子实体的版本 为0(因为它们未更改) 当我使用相同的测试用例,但使用ClientDto和Orika映射时, 在测试用

在我的数据库模型中,每个实体都有版本字段。 我有三个简单的实体(客户、债务、付款)和@OneToMany realtions。客户有很多债务。债务有很多偿还。 我还使用Orika进行类映射(dto->entity和entity->dto)

我有两个测试用例:

  • 我已经完全满足并坚持客户需求。然后我换一个 几乎每次更改后,客户只需保存一个属性。在测试用例的末尾 客户实体的版本是递增的。子实体的版本 为0(因为它们未更改)
  • 当我使用相同的测试用例,但使用ClientDto和Orika映射时, 在测试用例的末尾,我看到不仅客户端版本是 递增,但也是未更改的子实体
  • 我不明白这种行为,也不知道为什么会发生。 我创建了一个简单的项目,通过测试可以很容易地识别错误,请参阅:

    最重要的代码部分:

    客户:

    // necessary annotations
    public class ClientEntity extends BaseEntity {
    
    @Id
    @SequenceGenerator(sequenceName = "CLIENT_SEQUENCE", name = "CLIENT_SEQUENCE", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLIENT_SEQUENCE")
    private Long id;
    
    private String firstName;
    
    private String lastName;
    
    private String language;
    
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "client_id")
    private Set<DebtEntity> debts;
    }
    
    Orika转换器:

    @Component
    @Getter
    public class Converter {
    
    private MapperFacade mapper;
    
    @PostConstruct
    public void init() {
    
        var mapperFactory = new DefaultMapperFactory.Builder().build();
        registerMappings(mapperFactory);
        mapper = mapperFactory.getMapperFacade();
    }
    
    private void registerMappings(DefaultMapperFactory mapperFactory) {
    
        mapperFactory.classMap(BaseDto.class, BaseEntity.class).byDefault().register();
        mapperFactory.classMap(Client.class, ClientEntity.class).byDefault().register();
        mapperFactory.classMap(Debt.class, DebtEntity.class).byDefault().register();
        mapperFactory.classMap(Payment.class, PaymentEntity.class).byDefault().register();
    
        mapperFactory.classMap(BaseEntity.class, BaseDto.class).byDefault().register();
        mapperFactory.classMap(ClientEntity.class, Client.class).byDefault().register();
        mapperFactory.classMap(DebtEntity.class, Debt.class).byDefault().register();
        mapperFactory.classMap(PaymentEntity.class, Payment.class).byDefault().register();
    }
    }
    
    客户道:

    @RequiredArgsConstructor
    @Component
    public class ClientDao implements ClientPersistence {
    
    private final ClientRepository clientRepository;
    
    private final Converter converter;
    
    @Override
    public long save(Client client) {
    
        var clientEntity = converter.getMapper().map(client, ClientEntity.class);
        return clientRepository.save(clientEntity).getId();
    }
    
    @Override
    public Client getClientById(long id) {
    
        var client = clientRepository.getOne(id);
        return converter.getMapper().map(client, Client.class);
    }
    }
    
    客户端测试:

    // this test fails
    @Test
    public void shouldNotIncrementChildVersionAfterParentDtoSaved() {
    
        // given
        var client = Client.builder()
                .firstName("John")
                .lastName("Smith")
                .language("pl")
                .debts(Set.of(
                        Debt.builder()
                                .amount(BigDecimal.valueOf(25000))
                                .payments(Set.of(Payment.builder().amount(BigDecimal.valueOf(2500)).date(Date.from(Instant.now())).build()))
                                .build()))
                .build();
    
        // when
        long id = clientDao.save(client);
        var clientCopy1 = clientDao.getClientById(id);
    
        clientCopy1.setLanguage("en");
        id = clientDao.save(clientCopy1);
        var clientCopy2 = clientDao.getClientById(id);
    
        clientCopy2.setLanguage("en");
        id = clientDao.save(clientCopy2);
        var clientCopy3 = clientDao.getClientById(id);
    
        // then
        assertEquals(3, clientCopy3.getVersion());
        assertEquals(0, clientCopy3.getDebts().iterator().next().getVersion());
    }
    
    // this test passes
    @Test
    public void shouldNotIncrementChildVersionAfterParentEntitySaved() {
    
        // given
        var clientEntity = ClientEntity.builder()
                .firstName("John")
                .lastName("Smith")
                .language("pl")
                .debts(Set.of(
                        DebtEntity.builder()
                                .amount(BigDecimal.valueOf(25000))
                                .payments(Set.of(PaymentEntity.builder().amount(BigDecimal.valueOf(2500)).date(Date.from(Instant.now())).build()))
                                .build()))
                .build();
    
        // when
        var clientEntityCopy = clientRepository.save(clientEntity);
    
        clientEntityCopy.setLanguage("en");
        clientEntityCopy = clientRepository.save(clientEntityCopy);
    
        clientEntityCopy.setLanguage("ru");
        clientEntityCopy = clientRepository.save(clientEntityCopy);
    
        // then
        assertEquals(2, clientEntityCopy.getVersion());
        assertEquals(0, clientEntityCopy.getDebts().iterator().next().getVersion());
    }
    
    编辑


    我终于找到了解决这个问题的办法。我将带有@JoinColumn的单向@OneToMany关系更改为双向@OneToMany。
    但是我仍然不知道为什么它不适用于单向@OneToMany。

    您正在为
    BaseDto.version使用一个原语类型,它的默认值为0。因此,如果映射该对象,则为该版本初始化0。如果您直接创建实体,则会为
    BaseEntity.version初始化null,Hibernate会给它第一个值,我认为是1。

    您正在为
    BaseDto.version使用一个原语类型,它的默认值为0。因此,如果映射该对象,则为该版本初始化0。如果直接创建实体,则会为
    BaseEntity初始化null。version
    和Hibernate将为其提供第一个值,我认为是1。

    我将其更改为整数,但不幸的是仍然无法工作。有趣的是,当我没有填写最后@OneToMany collection(payments)时,它工作正常。您可以切换到在实体上使用属性访问器,即将JPA注释放在getter上,而不是字段上。然后,您可以在setter中设置断点,并查看为什么要设置version字段以及设置哪个值。我想这应该可以让你继续。我试过了,但在这个例子中,JPA迭代所有的setter并设置相同的值。我认为这个问题可能与嵌套的@OneToMany关系密切相关。正如我所说,当我将付款留空时,问题不会发生。我甚至尝试在没有Orika的情况下编写自己的映射程序,但结果是一样的。我终于找到了解决这个问题的方法。我将与JoinColumn的单向一元关系更改为双向一元关系。但我仍然不知道为什么它不适用于单向的OneToMany。我将它改为整数,不幸的是仍然不起作用。有趣的是,当我没有填写最后@OneToMany collection(payments)时,它工作正常。您可以切换到在实体上使用属性访问器,即将JPA注释放在getter上,而不是字段上。然后,您可以在setter中设置断点,并查看为什么要设置version字段以及设置哪个值。我想这应该可以让你继续。我试过了,但在这个例子中,JPA迭代所有的setter并设置相同的值。我认为这个问题可能与嵌套的@OneToMany关系密切相关。正如我所说,当我将付款留空时,问题不会发生。我甚至尝试在没有Orika的情况下编写自己的映射程序,但结果是一样的。我终于找到了解决这个问题的方法。我将与JoinColumn的单向一元关系更改为双向一元关系。但我仍然不知道为什么它不适用于单向的OneToMany。
    @RequiredArgsConstructor
    @Component
    public class ClientDao implements ClientPersistence {
    
    private final ClientRepository clientRepository;
    
    private final Converter converter;
    
    @Override
    public long save(Client client) {
    
        var clientEntity = converter.getMapper().map(client, ClientEntity.class);
        return clientRepository.save(clientEntity).getId();
    }
    
    @Override
    public Client getClientById(long id) {
    
        var client = clientRepository.getOne(id);
        return converter.getMapper().map(client, Client.class);
    }
    }
    
    // this test fails
    @Test
    public void shouldNotIncrementChildVersionAfterParentDtoSaved() {
    
        // given
        var client = Client.builder()
                .firstName("John")
                .lastName("Smith")
                .language("pl")
                .debts(Set.of(
                        Debt.builder()
                                .amount(BigDecimal.valueOf(25000))
                                .payments(Set.of(Payment.builder().amount(BigDecimal.valueOf(2500)).date(Date.from(Instant.now())).build()))
                                .build()))
                .build();
    
        // when
        long id = clientDao.save(client);
        var clientCopy1 = clientDao.getClientById(id);
    
        clientCopy1.setLanguage("en");
        id = clientDao.save(clientCopy1);
        var clientCopy2 = clientDao.getClientById(id);
    
        clientCopy2.setLanguage("en");
        id = clientDao.save(clientCopy2);
        var clientCopy3 = clientDao.getClientById(id);
    
        // then
        assertEquals(3, clientCopy3.getVersion());
        assertEquals(0, clientCopy3.getDebts().iterator().next().getVersion());
    }
    
    // this test passes
    @Test
    public void shouldNotIncrementChildVersionAfterParentEntitySaved() {
    
        // given
        var clientEntity = ClientEntity.builder()
                .firstName("John")
                .lastName("Smith")
                .language("pl")
                .debts(Set.of(
                        DebtEntity.builder()
                                .amount(BigDecimal.valueOf(25000))
                                .payments(Set.of(PaymentEntity.builder().amount(BigDecimal.valueOf(2500)).date(Date.from(Instant.now())).build()))
                                .build()))
                .build();
    
        // when
        var clientEntityCopy = clientRepository.save(clientEntity);
    
        clientEntityCopy.setLanguage("en");
        clientEntityCopy = clientRepository.save(clientEntityCopy);
    
        clientEntityCopy.setLanguage("ru");
        clientEntityCopy = clientRepository.save(clientEntityCopy);
    
        // then
        assertEquals(2, clientEntityCopy.getVersion());
        assertEquals(0, clientEntityCopy.getDebts().iterator().next().getVersion());
    }