繁体   English   中英

Spring Data JPA同时保存两个实体,“ user_id”列中为空值

[英]Spring Data JPA saving two entities at the same time, null value in column “user_id”

我的应用程序中有用户,用户中有工作明细,我使用一种方法来设置用户/工作明细数据,然后添加新用户或修改现有用户。

这是设置用户/工作数据的方法:

public WorkDetail setWorkerData(PatchWorkerRequest request, User user, WorkDetail workDetail) {

        if (request.getName() != null) {
            user.setName(request.getName());
        }

        if (request.getIdCode() != null) {
            user.setIdCode(request.getIdCode());
        }

        if (request.getEmail() != null) {
            user.setEmail(request.getEmail());
        }

        if (request.getPhone() != null) {
            user.setPhone(request.getPhone());
        }

        if (request.getAddress() != null) {
            user.setAddress(request.getAddress());
        }

        if (request.getSignatureLevel() != null) {
            user.setSignatureLevel(request.getSignatureLevel());
        }

        if (request.getAltContactRelation() != null) {
            user.setAltContactRelation(request.getAltContactRelation());
        }

        if (request.getAltContactPhone() != null) {
            user.setAltContactPhone(request.getAltContactPhone());
        }

        if (request.getRoles() != null) {
            user.setRoles(request.getRoles());
        }

        if (request.getStatus() != null) {
            user.setStatus(request.getStatus());
        }

        // Work details

        if (request.getJobRelation() != null) {
            workDetail.setJobRelation(request.getJobRelation());
        }

        if (request.getSalary() != null) {
            workDetail.setSalary(request.getSalary());
        }

        if (request.getDistricts() != null) {
            workDetail.setDistricts(request.getDistricts());
        }

        if (request.getCompetences() != null) {
            workDetail.setCompetences(request.getCompetences());
        }

        workDetail.setUser(user);
        user.setWorkDetail(workDetail);

        return workDetailRepository.save(workDetail);
    }

现在,使用以下代码可以很好地修改现有的工作程序:

public WorkDetail modifyWorker(Long workerId, PatchWorkerRequest request) {
        WorkDetail workDetail = this.getWorkDetailById(workerId);
        User user = userService.getUserById(workDetail.getUser().getId());
        return setWorkerData(request, user, workDetail);
    }

但是,当我尝试创建新用户/工人时,出现错误"null value in column "user_id" violates not-null constraint" 我认为这是因为workDetail和用户未正确连接。

这是创建新工作程序的方法:

public WorkDetail createWorker(PatchWorkerRequest request) {
        WorkDetail workDetail = new WorkDetail();
        User user = new User();
        String generatedPassword = userService.generatePassword(8);
        user.setPassword(passwordEncoder.encode(generatedPassword));
        emailService.sendMail("SYDA", new String[]{request.getEmail()},
                "Project SYDA",
                "New password: " + generatedPassword + ".);
        return setWorkerData(request, user, workDetail);
    }

另外,在保存用户后,有什么方法可以发送电子邮件,以便在发生错误时不会发送电子邮件?

实体:

用户:

@Entity
@Data
@NoArgsConstructor
@TypeDefs({
        @TypeDef(name = "pgsql_enum", typeClass = PostgreSQLEnumType.class)
})
@Table(name = "user_acc")
public class User implements Serializable {

    @Id
    @Column(unique = true, nullable = false, columnDefinition = "serial")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "id_code")
    private BigInteger idCode;

    @Column(name = "email", nullable = false)
    private String email;

    @Column(name = "address")
    private String address;

    @Column(name = "phone")
    private BigInteger phone;

    @Column(name = "alt_contact_relation")
    private String altContactRelation;

    @Column(name = "alt_contact_phone")
    private BigInteger altContactPhone;

    @Column(name = "password", nullable = false)
    @JsonIgnore
    private String password;

    @JsonIgnore
    @Column(name = "create_time", nullable = false, updatable = false)
    private Date createTime = new Date();

    @JsonIgnore
    @Column(name = "update_time", nullable = false)
    private Date updateTime = new Date();

    @Column(name = "status", nullable = false, columnDefinition = "active_status")
    @Enumerated(EnumType.STRING)
    @Type(type = "pgsql_enum")
    private UserStatus status;

    @OneToOne
    @PrimaryKeyJoinColumn
    @JsonIgnore
    private WorkDetail workDetail;

    @OneToMany(mappedBy = "user")
    private List<UserFile> userFiles = new ArrayList<>();

    @ManyToOne
    @JoinColumn(name = "signature_level_id")
    private SignatureLevel signatureLevel;

    @ManyToMany(fetch = FetchType.EAGER, targetEntity = UserRole.class)
    @JoinTable(name = "user_has_user_role",
            joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = { @JoinColumn(name = "user_role_id", referencedColumnName = "id")}
    )
    private Set<UserRole> roles = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER, targetEntity = Mechanism.class)
    @JoinTable(name = "user_has_mechanism",
            joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = { @JoinColumn(name = "mechanism_id", referencedColumnName = "id")}
    )
    private Set<Mechanism> mechanisms = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER, targetEntity = Service.class)
    @JoinTable(name = "user_has_service",
            joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id")},
            inverseJoinColumns = { @JoinColumn(name = "service_id", referencedColumnName = "id")}
    )
    private Set<Service> services = new HashSet<>();

    @PreUpdate
    @PrePersist
    public void onCreateOnUpdate() {
        updateTime = new Date();
    }

    public enum UserStatus {
        active, temporarily_inactive, inactive
    }
}

工作细节:

@Entity
@Data
@Table(name = "work_detail")
public class WorkDetail {

    @Id
    @Column(unique = true, nullable = false, columnDefinition = "serial")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "salary")
    private float salary;

    @OneToOne(mappedBy = "workDetail",fetch = FetchType.LAZY, optional = true)
    @PrimaryKeyJoinColumn
    private User user;

    @Column(name = "create_time", nullable = false, updatable = false)
    @JsonIgnore
    private Date createTime = new Date();

    @Column(name = "update_time", nullable = false)
    @JsonIgnore
    private Date updateTime = new Date();

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "workDetail")
    private List<UserLeave> userLeaves = new ArrayList<>();

    @ManyToOne
    @JoinColumn(name = "job_relation_id")
    private JobRelation jobRelation;

    @ManyToMany(fetch = FetchType.EAGER, targetEntity = District.class)
    @JoinTable(name = "work_detail_has_district",
            joinColumns = { @JoinColumn(name = "work_detail_id", referencedColumnName = "id")},
            inverseJoinColumns = { @JoinColumn(name = "district_id", referencedColumnName = "id")}
    )
    private Set<District> districts = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER, targetEntity = Competence.class)
    @JoinTable(name = "work_detail_has_competence",
            joinColumns = { @JoinColumn(name = "work_detail_id", referencedColumnName = "id")},
            inverseJoinColumns = { @JoinColumn(name = "competence_id", referencedColumnName = "id")}
    )
    private Set<Competence> competences = new HashSet<>();

    @PreUpdate
    @PrePersist
    public void onCreateOnUpdate() {
        updateTime = new Date();
    }
}

db表:

-----------------------
-- User table
-----------------------

CREATE TABLE IF NOT EXISTS user_acc (
  id SERIAL NOT NULL PRIMARY KEY,
  name text NOT NULL,
  id_code numeric NOT NULL,
  email text NOT NULL UNIQUE,
  address text NULL,
  alt_contact_relation text NULL,
  alt_contact_phone numeric NULL,
  signature_level_id integer NULL,
  username text NOT NULL,
  password text NOT NULL,
  create_time TIMESTAMP without TIME ZONE DEFAULT now() NOT NULL,
  update_time TIMESTAMP without TIME ZONE DEFAULT now() NOT NULL,
  status active_status NOT NULL DEFAULT 'active',
  CONSTRAINT FK_user_signature_level FOREIGN KEY (signature_level_id) REFERENCES signature_level (id)
  ON DELETE NO ACTION ON UPDATE NO ACTION
);

-----------------------
-- User: work detail table
-----------------------

CREATE TABLE IF NOT EXISTS work_detail (
  id SERIAL NOT NULL PRIMARY KEY,
  salary decimal NULL,
  job_relation_id integer NOT NULL,
  user_id integer NOT NULL,
  create_time TIMESTAMP without TIME ZONE DEFAULT now() NOT NULL,
  update_time TIMESTAMP without TIME ZONE DEFAULT now() NOT NULL,
  CONSTRAINT FK_work_detail_user FOREIGN KEY (user_id) REFERENCES user_acc (id)
  ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT fk_work_details_job_relations1 FOREIGN KEY (job_relation_id)
    REFERENCES job_relation (id)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

您需要先保存user然后再将其添加到workDetail 新的User对象没有id,这就是为什么要获取该异常的原因。 像这样:

public WorkDetail createWorker(PatchWorkerRequest request) {
        WorkDetail workDetail = new WorkDetail();
        User user = new User();
        String generatedPassword = userService.generatePassword(8);
        user.setPassword(passwordEncoder.encode(generatedPassword));
        user = userRepository.save(user);
        emailService.sendMail("SYDA", new String[]{request.getEmail()},
                "Project SYDA",
                "New password: " + generatedPassword + ".);
        return setWorkerData(request, user, workDetail);
    }

或者,您可以在setWorkerData方法内添加saveUser调用。

...
 if (request.getStatus() != null) {
            user.setStatus(request.getStatus());
        }
user = userRepository.save(user);
...

在您的setWorker()方法中,您尝试为workDetail对象设置user ,但是user对象没有其user_id因为该用户对象是分离模式,并且仍然没有user_id与用户对象相关联。

 //some code in your setWorker() Method.
 workDetail.setUser(user);   //you try to set a detached User Object which doesn't have it's id.
 user.setWorkDetail(workDetail);

 return workDetailRepository.save(workDetail);

因此,可以在设置之前保存该user ,并确保将user Object持久保存到database中。

在上面的代码之前添加此行。

user = userRepository.save(user); // add this line....
workDetail.setUser(user);   //now your User Object will have it's id.
user.setWorkDetail(workDetail);

return workDetailRepository.save(workDetail);

还有另一种无需调用save()方法即可执行此操作的方法,只需使用级联的概念即可获取更多信息, 请参见此 链接。

您可以使用spring-boot-starter-mail依赖项来完成这项工作

这意味着您尝试保存workdetail对象时未保存用户对象。 因此,没有要放置的user_id,因此没有null值。 可以给您邮寄实体吗? (特别是它们之间的映射)。 我想,如果您希望同时保存两个实体,则应该使用@OneToOne(cascade = CascadeType.PERSIST)类的东西。

您的映射错误。
这是您应该做的:
在WorkDetail中:
@OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "user_id") private User user;

在用户中:
@OneToOne(mappedBy = "user") @JsonIgnore private WorkDetail workDetail;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM