Spring Data REST使用null变量调用`save`接收对象

时间:2018-03-04 23:38:17

标签: java spring postgresql hibernate spring-data

我正在继续开发一个系统,该系统在前端使用React JavaScript库(及相关内容),在后端使用Spring Data REST,Hibernate,PostgreSQL及相关内容。

该系统将由拥有一个或多个公司及其客户的人使用。这意味着大多数/所有模型对象都将引用它们所属的Company(ies)。此外,公司所有者将拥有一些Employee s,这些Employee将在此系统上具有更高级别的访问权限(或者这些将是所有者自己)。

我需要实现一种功能,当公司插入数据库时​​,也会插入员工。此外,如果一个失败,两者都必须失败。由于模型的设置方式,我发送一个Company对象进行保存,并在其中发送新的employee: { // ..., company: { // .... } } ,就像这样(使用Axios):

save

问题是,当在后端调用Company方法时,Employee对象的null成员是Employee。我尝试过一些事情,比如弄乱关系,在Company对象中添加Company列表,分别传递package xxx.model.common; import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.validation.constraints.NotNull; import lombok.Data; @Data @MappedSuperclass public abstract class Record { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) protected Long id; @NotNull @Column(name = "deleted") protected Boolean isDeleted = false; @NotNull @Column(name = "enabled") protected Boolean isEnabled = true; } 对象,但没有任何效果。

我还能尝试什么?以下是一些课程:

Record.java

package xxx.model;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;

import com.fasterxml.jackson.annotation.JsonManagedReference;
import xxx.common.Record;
// ...

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper=false)
@Entity
@Table(name="company")
@AttributeOverrides( { @AttributeOverride(name = "id", column = @Column(name = "id_company")) } )
public class Company extends Record {

    /*
     * ...
     */

    // Necessary for Hibernate
    protected Company() {}

    public Company(/* ... */) {
        /*
         * ...
         */
    }
}

Company.java

package xxx.model.common;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotBlank;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper=false)
@MappedSuperclass
public abstract class Registry extends Record {

    @NotBlank
    @Column(name = "code", length = 15)
    protected String code;

    @NotBlank
    @Column(name = "name", length = 40)
    protected String name;
}

Registry.java

package xxx.model.common;

import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;

import com.fasterxml.jackson.annotation.JsonBackReference;
import xxx.model.Company;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper=false)
@MappedSuperclass
public class RegistrySingleCompany extends Registry {

    @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE }, optional= false)
    @JoinColumn(name="id_company")
    protected Company company;
}

RegistrySingleCompany.java

package xxx.model;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import xxx.model.common.RegistrySingleCompany;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper=false)
@Entity
@Table(name="employee")
@AttributeOverrides( { @AttributeOverride(name = "id", column = @Column(name = "id_employee")) } )
public class Employee extends RegistrySingleCompany {

    /*
     * ...
     */

    // Necessary for Hibernate
    protected Employee() {}
}

Employee.java

package xxx.repository.custom;

import org.springframework.data.repository.query.Param;

import xxx.model.Employee;

public interface EmployeeRepositoryCustom {

    <S extends Employee> S save(S entity);
}

EmployeeRepositoryCustom.java

package xxx.repository.custom;

import javax.persistence.PersistenceContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestBody;

import xxx.model.Employee;

public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom {

    @Override
    @Transactional
    public <S extends Employee> S save(@RequestBody S entity) {
        /*
         * ...
         */
        return entity;
    }
}

EmployeeRepositoryCustomImpl.java

package xxx.model.projection;

import org.springframework.data.rest.core.config.Projection;

import xxx.model.Employee;

@Projection(name = "employeeProjection", types = { Employee.class }) 
public interface EmployeeProjection {

    Boolean getIsDeleted();

    Boolean getIsEnabled();

    String getCode();

    String getName();

    /*
     * ...
     */
}

EmployeeProjection.java

package xxx.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import xxx.model.Employee;
import xxx.model.projection.EmployeeProjection;
import xxx.repository.custom.EmployeeRepositoryCustom;

@RepositoryRestResource(collectionResourceRel = "employee", path = "employees", excerptProjection = EmployeeProjection.class)
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long>, EmployeeRepositoryCustom {}

EmployeeRepository.java

conda is a pip replacement

提前致谢。

修改:添加了缺失的课程。

1 个答案:

答案 0 :(得分:0)

如前所述,我尝试过的一件事是在Employee对象中添加Company列表,这意味着使用Company的存储库而不是Employee保存两个对象的是一个,但另一个对象也是null。但是,我的同事发现,通过在exported = false内使用@RepositoryRestResource(),可以正确接收该值。

那会搞砸其他事情,所以我们找到了以下临时解决方案:

  • 创建exported = false存储库(EmployeeWrapper),其唯一目的是提供必要的Employee数据,以便在save内构建新数据库。
  • 不是在Employee内添加Company列表,而是添加EmployeeWrapper列表。
  • EmployeeWrapper也引用Company

我们仍在努力采用更正确的方法。

更新:更正确的方法:

我的同事还发现,通过向@Transient添加Employee Company列表,可以收到正确填写的Employee对象以保存它。我不知道它是否在存储库中有效,因为由于其他限制,我们开始使用@RepositoryRestController并且正在接收Company作为@RequestBody org.springframework.hateoas.Resource<Company> resource

我们仍然希望找到更好的解决方案,因为Employee中的Company列表未在我们的模型中进行规划,更糟糕的是,我们需要将其他内容列表用于其他方法

更新:更好的方法:

再尝试一下,我们创建了一个POJO,其中包含我们需要的实体,并在控制器中以与以前相同的方式接收这些实体。效果很好。

但是,我们仍然不满意。理想情况下,我们希望收到要保存的Employee,并将Company保存在其中,并立即保存。