spring-data-jpa Spring JPA保存父对象不是保存子对象-已解决(位于注解末尾)

eiee3dmh  于 2022-11-10  发布在  Spring
关注(0)|答案(2)|浏览(224)

我有一个csv文件,其中有一个员工和项目信息列表(每个员工有多个项目)。我上传文件,解析csv文件,分别建立父子关系-〉员工和项目,并将其保存到数据库。
下面是我的Employee实体类(我尝试了注解部分,但没有成功)

@Entity
@Table(name = "employees")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @NotNull
    private String name;
    @NotNull
    private String empId;
    @NotNull
    private String department;

    //@OneToMany(fetch = FetchType.LAZY, mappedBy = "transcript", cascade = CascadeType.ALL) //tried didn't work
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "employee", orphanRemoval = true)
    private List<Project> projects;

    public Employee(String name, String empId, String department) {
        this.name = name;
        this.empId = empId;
        this.department = department;
    }
}

下面是我的项目实体类

@Entity
@Table(name = "projects")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String projectName;
    private String projectCode;
        private Instant projectStartDate;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "employee_id", nullable = false)
    @JsonBackReference
    private Employee employee;

    public Project(String name, String code, Instant time) {
        this.projectName = name;
        this.projectCode = code;
        this.projectStartDate = time;
    }
}

这是我试图保存Employee对象的位置:

@Transactional
    public void uploadEmployees(MultipartFile file) {
        try {
//calls csv helper that does all the parsing and brings into Employee model object format
            Set<Employess> employees = CSVHelper.csvToEmployess(file.getInputStream(), "2");
            employeeRepository.saveAll(employees);
            System.out.println("I processed all the records of cdv into java");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }catch (Exception e ){
            throw new RuntimeException(e.getMessage());
        }
    }

上述方法会掷回:

2022-09-11T22:30:08.438-05:00 ERROR 63321 --- [nio-8086-exec-5] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: null value in column "employee_id" of relation "projects" violates not-null constraint
  Detail: Failing row contains (6, p1, 123, 0184-06-08T01:07:47Z, null).

如果我把id的生成类型改为@GeneratedValue(策略= GenerationType.AUTO):我得到下面的异常:

2022-09-12T00:55:09.465-05:00  WARN 73014 --- [nio-8086-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 42P01
2022-09-12T00:55:09.465-05:00 ERROR 73014 --- [nio-8086-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: relation "hibernate_sequence" does not exist
  Position: 17
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
    at jdk.proxy2/jdk.proxy2.$Proxy133.saveAll(Unknown Source)

就在执行saveAll方法之前,我尝试使用调试器查看我的雇员列表的外观,结果如下所示:

Employee(id=0, name="test", empId="4511504557911789", department="JJ967W"
        projects=[
                Project(id=0, projectName="p1", projectCode="123", projectStartDate="0184-06-08T01:07:47Z", employee=null),
                Project(id=0, projectName="p2", projectCode="345", projectStartDate="0184-06-08T01:07:47Z", employee=null)
                ]
        )

我认为employee=null是有意义的,因为它还没有保存到数据库。
请帮助我,在我错过了什么,在这里是导致这打破。非常感谢你花时间在提供帮助。

已更新

添加我正在添加解析CSV和构建Employee和Project对象的部分

public static Set<Employee> csvToTranscripts(InputStream is) throws IOException {
        try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
             CSVParser csvParser = new CSVParser(fileReader,
                     CSVFormat.DEFAULT.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());) {
            Set<Employee> employees = new HashSet<>();
            List<CSVRecord> csvRecordsList = csvParser.getRecords();
            Employee employee = null;
            List<String> empIds = new ArrayList<>();
            List<Project> projects = null;
            //iterate through list and create project list for new emp_id
            for(CSVRecord csvRecord : csvRecordsList){
                if(employees.isEmpty() || !empIds.contains(csvRecord.get("EMP_ID"))){
                    employee = new Employee(
                            csvRecord.get("NAME"),
                            csvRecord.get("EMP_ID"),
                            csvRecord.get("DEPARTMENT")
                    );
                    empIds.add(csvRecord.get("EMP_ID")); //this is mainly to check for unique emp id
                    projects = new ArrayList<>();
                }
                Project project = new Project(csvRecord.get("NAME"),
                        csvRecord.get("CODE"),
                        formatToInstant(csvRecord.get("TIME")) );
                project.setEmployee(employee);//setting employee to project here
                projects.add(project);
                employee.setProjects(projects); //setting projects list to employee here
                employees.add(employee);
            }
            return employees;
        } catch (IOException e) {
            throw new RuntimeException("fail to parse CSV file: " + e.getMessage());
        }
    }

已解决*******************************************************************************************************************************************************************************

project.setEmployee(employee);
mpbci0fu

mpbci0fu1#

进一步评论@M.代努姆-在Employee类中声明一个类似这样的方法,并使用它向Employee添加一个项目,以确保双向关系保持同步

public void addProject(Project project) {
        if (projects == null) {
            projects = new ArrayList<>();
        }
        project.setEmployee(this);
        projects.add(project);
    }
piwo6bdm

piwo6bdm2#

我认为employee=null是有意义的,因为它还没有保存到DB中。
这是错误的。如果你保存一个双向关系的项目,那么你就不能有一个孤立的Project存在而没有一个Employee的情况。所以在调用任何CrudRepository.save*()之前,你必须确保所有的projects都引用了一些Employee
通常在这种情况下,当您将项目添加到员工时,您可以执行以下操作:

// method of Employee class
public void addAll(Projects projects) {
  for (Project : projects) {
    project.setEmployee(this);
  }
  this.projects.addAll(projects);
}

相关问题