jpa Java Hibernate将实体和子实体一起保存

lokaqttq  于 12个月前  发布在  Java
关注(0)|答案(1)|浏览(96)

我有一个规则实体和一个测试实体(一对多相关),当创建一个规则时,会生成一个ruleId,我想使用ruleId进行测试。实体:

package io.avalor.webserver.rule;

import com.vladmihalcea.hibernate.type.array.EnumArrayType;
import com.vladmihalcea.hibernate.type.array.ListArrayType;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import io.avalor.webserver.account.Account;
import io.avalor.webserver.customquery.CustomQuery;
import io.avalor.webserver.persistency.AbstractEntity;
import io.avalor.webserver.rule.ruletest.RuleTest;
import io.avalor.webserver.rule.unittest.RuleUnitTest;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.*;

import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Set;

@Entity
@Table
@SQLDelete(sql = "UPDATE rule SET deleted = true WHERE rule_id=?")
@Where(clause = "deleted=false")
@TypeDef(name = "list-array", typeClass = EnumArrayType.class, parameters = {@org.hibernate.annotations.Parameter(name = EnumArrayType.SQL_ARRAY_TYPE, value = "varchar")})
@TypeDef(name = "json", typeClass = JsonBinaryType.class)
@TypeDef(name = "list", typeClass = ListArrayType.class)
@Getter
@Setter
public class Rule extends AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "rule_id")
    private String id;

    @Column
    @NotBlank
    private String name;

    @OneToMany(fetch = FetchType.EAGER)
    @Fetch(value = FetchMode.SUBSELECT)
    @JoinTable(
            name = "rule_unit_test",
            joinColumns = {@JoinColumn(name = "rule_id", updatable = false)},
            inverseJoinColumns = {@JoinColumn(name = "test_id", updatable = false)}
    )
    private List<RuleUnitTest> unitTests;
}
package io.avalor.webserver.rule.unittest;

import com.fasterxml.jackson.databind.JsonNode;
import io.avalor.webserver.persistency.AbstractEntity;
import io.avalor.webserver.rule.Rule;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.*;

import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

@Entity
@Table
@Where(clause = "deleted=false")
@SQLDelete(sql = "UPDATE rule_unit_test SET deleted = true WHERE test_id=?")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class RuleUnitTest {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "test_id")
    private String id;

    @NotNull
    @JoinColumn(name = "rule_id", updatable = false)
    @ManyToOne(fetch = FetchType.LAZY)
    private Rule rule;

    @Column
    @NotBlank
    private String name;

    @NotEmpty
    @Type(type = "json")
    @Column(name = "test_data")
    private List<JsonNode> testData;
}

我有一个具有以下方法的规则服务:

@Transactional
    public RuleDto create(RuleDto ruleDto) {
        Rule rule = ruleMapper.dtoToEntity(ruleDto);
        Rule savedRule = ruleRepository.save(rule);

        savedRule = saveUnitTestsIfExists(savedRule,ruleDto.getUnitTests());
        // ruleRepository.save(savedRule);
        return ruleMapper.entityToDto(savedRule);
    }

    private Rule saveUnitTestsIfExists(Rule rule, List<RuleUnitTestDto> unitTestsDto) {
        if (CollectionUtils.isNotEmpty(unitTestsDto)) {
            return unitTestService.create(rule,unitTestsDto);
        }
        return rule;
    }

下面是unittestService中的代码:

public Rule create(Rule rule, List<RuleUnitTestDto> unitTestsDto) {
        List<RuleUnitTestDto> limitedRuleUnitTestDtos = unitTestsDto;

        if (unitTestsDto.size() > MAX_TESTS_PER_RULE) {
            limitedRuleUnitTestDtos = unitTestsDto.subList(0, MAX_TESTS_PER_RULE);
        }
        List<RuleUnitTest> unitTests = ruleUnitTestMapper.buildBuildUnitTestFromUnitTest(rule, limitedRuleUnitTestDtos);

        rule.setUnitTests(unitTestRepository.saveAll(unitTests));
        return rule;
    }

制图员:

package io.avalor.webserver.rule;

import io.avalor.webserver.rule.unittest.RuleUnitTest;
import io.avalor.webserver.rule.unittest.RuleUnitTestDto;
import org.mapstruct.*;

import java.util.*;

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public abstract class RuleMapper {

    @Mapping(source = "account.id", target = "accountId")
    @Mapping(target = "dataSourceTypes", ignore = true)
    public abstract RuleDto entityToDto(Rule rule);

    @Mapping(target = "account.id", source = "accountId")
    @Mapping(target = "dataSourceTypes", ignore = true)
    public abstract Rule dtoToEntity(RuleDto ruleDto);

    @AfterMapping
    public void setRuleProperties(@MappingTarget Rule rule, RuleDto ruleDto) {
        if (rule.getId() != null) {
            rule.setUnitTests(buildBuildUnitTestFromUnitTest(rule, ruleDto.getUnitTests()));
        } else {
            rule.setUnitTests(null);
        }
    }

    @AfterMapping
    public RuleDto enrichDto(@MappingTarget RuleDto ruleDto, Rule rule) {
        if (rule.getUnitTests() != null) {
            ruleDto.setUnitTests(rule.getUnitTests().stream().map(unitTest -> {
                RuleUnitTestDto unitTestDto = new RuleUnitTestDto();
                unitTestDto.setId(unitTest.getId());
                unitTestDto.setName(unitTest.getName());
                unitTestDto.setTestData(unitTest.getTestData());
                unitTestDto.setRuleId(rule.getId());
                return unitTestDto;
            }).toList());
        }
        return ruleDto;
    }

    public List<RuleUnitTest> buildBuildUnitTestFromUnitTest(Rule rule, List<RuleUnitTestDto> unitTestDtos) {
        if (unitTestDtos == null)
            return Collections.emptyList();
        List<RuleUnitTest> unitTestsList = new ArrayList<>();

        for (RuleUnitTestDto unitTestDto : unitTestDtos) {
            unitTestsList.add(new RuleUnitTest(null, rule, unitTestDto.getName(), unitTestDto.getTestData()));
        }
        return unitTestsList;
    }
}

我正在尝试发送以下身体请求:

{
    "name": "rule1",
    "unitTests":[{
        "name":"blah blah",
        "testData":[{"a":"b"}]
    }]
}

当尝试保存一个规则和一个单元测试时,我得到以下错误(说name和testData是null,这在调试时不是真的):

ERROR: null value in column "name" of relation "rule_unit_test" violates not-null constraint
  Detail: Failing row contains (p0n9vr, 07rplw, null, null).

我真的不知道为什么会这样,有什么想法吗?

jtw3ybtb

jtw3ybtb1#

你可能想看看JPA教程,了解双向OneToMany和ManyToOneMap是如何工作的,但你可能应该在Rule->RuleUnitTestMap中使用'mappedby':

@OneToMany(mappedBy="rule", fetch = FetchType.EAGER)
  @Fetch(value = FetchMode.SUBSELECT)
  private List<RuleUnitTest> unitTests;

还要注意的是,在格式化JSON数据时,您需要确保此关系的两端都已设置-或者更重要的是,每个RuleUnitTest.rule引用都已正确设置,因为这是拥有(因此控制)外键列值的关系。

相关问题