Spring Data JPA сохраняет две сущности одновременно, нулевое значение в столбце "user_id" - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть пользователи в моем приложении, и у пользователей есть рабочие данные, я использую один метод для установки данных пользователя / рабочих данных, а затем либо добавляю нового пользователя, либо изменяю существующего.

Этоспособ установки данных пользователя / работы:

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
    }
}

WorkDetail:

@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();
    }
}

БД:

-----------------------
-- 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);

Ответы [ 5 ]

0 голосов
/ 28 февраля 2019

Ваше отображение неверно.
Вот что вы должны сделать:
в WorkDetail:
@OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "user_id") private User user;

в User:
@OneToOne(mappedBy = "user") @JsonIgnore private WorkDetail workDetail;

0 голосов
/ 26 февраля 2019

В вашем методе setWorker() вы пытаетесь установить user для workDetail Объект, но 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 Объект сохраняется в базе данных.

добавьте эту строку перед кодом выше ..

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(), просто используя концепцию каскадное , чтобы получить более подробную информацию с помощью Ссылка здесь

0 голосов
/ 26 февраля 2019

Вам необходимо сохранить user, прежде чем добавить его в workDetail.Новый объект User не имеет идентификатора, и именно поэтому вы получаете это исключение.Примерно так:

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);
    }

или вы можете добавить вызов saveUser внутри метода setWorkerData.

...
 if (request.getStatus() != null) {
            user.setStatus(request.getStatus());
        }
user = userRepository.save(user);
...
0 голосов
/ 26 февраля 2019

Это означает, что пользовательский объект не сохраняется при попытке сохранить объект workdetail.Так что нет user_id, чтобы поставить, следовательно, нулевое значение.Не могли бы вы опубликовать ваши лица, пожалуйста?(особенно отображение между ними).Я думаю, у вас должно быть что-то вроде @OneToOne(cascade = CascadeType.PERSIST), если вы хотите сохранить обе сущности одновременно.

0 голосов
/ 26 февраля 2019

Вы можете использовать зависимость spring-boot-starter-mail, чтобы получить эту работу

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...