Изменение всех id сущностей в spring

Всем привет Я новичок в spring. Пробую писать приложение. Столкнулся с проблемой. Есть сущность Statement. Она содержит список List. Проблема в том, что если введено 2 статуса с одинаковым idStatus и редактирую один из них, то происходит автоматическое изменение idStatus другой записи из List. У сущностей переопределены equals и hashCode, но проблема не решилась. Подскажите в какую сторону копать. Вот собственно куски кода

package by.ic.model;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.lang.Nullable;

@MappedSuperclass
public abstract class AbstractBaseEntity implements Serializable {
    private static final long serialVersionUID = 5269025572367966131L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Integer id;
    
    @Column(name = "note")
    @Nullable
    private String note;
    
    @Column(name = "d_form")
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss")
    private Date dForm;
    
    @Column(name = "d_change")
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss")
    private Date dChange;
    
    @Column(name = "pa")
    private Integer pa;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public Date getdForm() {
        return dForm;
    }

    public void setdForm(Date dForm) {
        this.dForm = dForm;
    }

    public Date getdChange() {
        return dChange;
    }

    public void setdChange(Date dChange) {
        this.dChange = dChange;
    }

    public Integer getPa() {
        return pa;
    }

    public void setPa(Integer pa) {
        this.pa = pa;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AbstractBaseEntity other = (AbstractBaseEntity) obj;
        return Objects.equals(id, other.id);
    }
}

Сущность Statement

package by.ic.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.springframework.format.annotation.DateTimeFormat;

import by.ic.model.user.User;

@Entity(name = "Statement")
@Table(name = "statement")
public class Statement extends AbstractBaseEntity implements Serializable {
    private static final long serialVersionUID = 1612993944763267493L;

    @ManyToOne(targetEntity = Organ.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "code_organ", referencedColumnName = "id")
    private Organ organ;
    
    @ManyToOne(targetEntity = StatementType.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "code_type", referencedColumnName = "id")
    private StatementType type;
    
    @Column(name = "year_reg")
    private Integer yearReg;
    
    @Column(name = "reg_number")
    private Integer regNumber;
    
    /*@Valid
    @NotNull(message = "'Дата' должна быть заполнена")*/
    @Column(name = "date_receipt")
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(pattern = "dd.MM.yyyy")
    private Date dateReceipt;
    
    @Column(name = "date_reg")
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(pattern = "dd.MM.yyyy")
    private Date dateReg;
    
    @Valid
    @OneToOne(targetEntity =  Person.class, cascade = CascadeType.ALL)
    @JoinColumn(name = "id_person", nullable = false)
    private Person person;  
        
    @Valid
    @ManyToOne(targetEntity = PaymentType.class)
    @JoinColumn(name = "сode_payment", referencedColumnName = "id")
    private PaymentType paymentType;
    
    @NotNull(message = "'№ бланка' должен быть заполнен")
    @Column(name = "blank_number")
    private Long blankNumber;

    @ManyToOne(targetEntity = User.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "id_user", referencedColumnName = "id", updatable = false, insertable = false)
    private User user;
    
    @OneToMany(mappedBy = "statement", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<Status> statusList = new ArrayList<>();
    
    @OneToOne(mappedBy = "statement", cascade = CascadeType.ALL)
    private MarkLocation markLocation;
    
    @OneToOne(mappedBy = "statement", cascade = CascadeType.ALL)
    private MarkDestroy markDestroy; 
    
    public Organ getOrgan() {
        return organ;
    }
    
    public void setOrgan(Organ organ) {
        this.organ = organ;
    }
    
    public StatementType getType() {
        return type;
    }
    
    public void setType(StatementType type) {
        this.type = type;
    }
    
    public Integer getYearReg() {
        return yearReg;
    }

    public void setYearReg(Integer yearReg) {
        this.yearReg = yearReg;
    }

    public Integer getRegNumber() {
        return regNumber;
    }

    public void setRegNumber(Integer regNumber) {
        this.regNumber = regNumber;
    }

    public Date getDateReceipt() {
        return dateReceipt;
    }
    
    public void setDateReceipt(Date dateReceipt) {
        this.dateReceipt = dateReceipt;
    }
    
    public Date getDateReg() {
        return dateReg;
    }

    public void setDateReg(Date dateReg) {
        this.dateReg = dateReg;
    }

    public Person getPerson() {
        return person;
    }
    
    public void setPerson(Person person) {
        this.person = person;
    }
    
    public PaymentType getPaymentType() {
        return paymentType;
    }
    
    public void setPaymentType(PaymentType paymentType) {
        this.paymentType = paymentType;
    }
    
    public Long getBlankNumber() {
        return blankNumber;
    }

    public void setBlankNumber(Long blankNumber) {
        this.blankNumber = blankNumber;
    }
    
    public User getUser() {
        return user;
    }
    
    public void setUser(User user) {
        this.user = user;
    }
    
    public List<Status> getStatusList() {
        return statusList;
    }
    
    public void setStatusList(List<Status> statusList) {
        this.statusList = statusList;
    }
    
    public MarkLocation getMarkLocation() {
        return markLocation;
    }
    
    public void setMarkLocation(MarkLocation markLocation) {
        this.markLocation = markLocation;
    }
    
    public MarkDestroy getMarkDestroy() {
        return markDestroy;
    }
    
    public void setMarkDestroy(MarkDestroy markDestroy) {
        this.markDestroy = markDestroy;
    }
}

Сущность Status

package by.ic.model;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;

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.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.format.annotation.DateTimeFormat;

import by.ic.model.user.User;

@Entity
@Table(name = "status")
public class Status extends AbstractBaseEntity implements Serializable, Comparable<Status> {
    private static final long serialVersionUID = 3687958201400103943L;
    
    @ManyToOne(targetEntity = StatusType.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "code_status", referencedColumnName = "id")
    private StatusType statusType;
    
    @Column(name = "prefix_out_number")
    private String prefixOutNumber;
    
    @Column(name = "out_number")
    private String outNumber;
    
    @ManyToOne(targetEntity = Organ.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "code_organ", referencedColumnName = "id", nullable = true)
    private Organ organ;
    
    @Column(name = "date_status")
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(pattern = "dd.MM.yyyy")
    private Date dateStatus;

    @ManyToOne(targetEntity = User.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "id_user", referencedColumnName = "id")
    private User user;
    
    @ManyToOne(targetEntity = Statement.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL )
    @JoinColumn(name = "id_statement", referencedColumnName = "id" )
    private Statement statement;
        
    public StatusType getStatusType() {
        return statusType;
    }
    
    public void setStatusType(StatusType statusType) {
        this.statusType = statusType;
    }

    public String getPrefixOutNumber() {
        return prefixOutNumber;
    }

    public void setPrefixOutNumber(String prefixOutNumber) {
        this.prefixOutNumber = prefixOutNumber;
    }

    public String getOutNumber() {
        return outNumber;
    }

    public void setOutNumber(String outNumber) {
        this.outNumber = outNumber;
    }

    public Organ getOrgan() {
        return organ;
    }

    public void setOrgan(Organ organ) {
        this.organ = organ;
    }

    public Date getDateStatus() {
        return dateStatus;
    }
    
    public void setDateStatus(Date dateStatus) {
        this.dateStatus = dateStatus;
    }
    
    public User getUser() {
        return user;
    }
    
    public void setUser(User user) {
        this.user = user;
    }
    
    public Statement getStatement() {
        return statement;
    }
    
    public void setStatement(Statement statement) {
        this.statement = statement;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + Objects.hash(dateStatus, organ, outNumber,
                prefixOutNumber, statement, statusType, user);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        Status other = (Status) obj;
        return Objects.equals(dateStatus, other.dateStatus)
                && Objects.equals(organ, other.organ)
                && Objects.equals(outNumber, other.outNumber)
                && Objects.equals(prefixOutNumber, other.prefixOutNumber)
                && Objects.equals(statement, other.statement)
                && Objects.equals(statusType, other.statusType)
                && Objects.equals(user, other.user);
    }

    @Override
    public int compareTo(Status status) {
        if (this.getDateStatus().after(status.getDateStatus())) {
            return 1;
        }
        if (this.getDateStatus().before(status.getDateStatus())) {
            return -1;
        }
        return this.getId() - status.getId();
    }
}

StatusType

package by.ic.model;

import java.io.Serializable;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "status_type")
public class StatusType implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;
    
    @Column(name = "name")
    private String name;
    
    @Column(name = "short_name")
    private String shortName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getShortName() {
        return shortName;
    }

    public void setShortName(String shortName) {
        this.shortName = shortName;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, shortName);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StatusType other = (StatusType) obj;
        return Objects.equals(id, other.id) && Objects.equals(name, other.name)
                && Objects.equals(shortName, other.shortName);
    }
}

Кусок контроллера для редактирования Статуса

@RequestMapping(value = "/statement/actions", params = "editStatus")
    public String editStatus(HttpSession session,
                             Model model,
                             @ModelAttribute("statement") Statement statement,
                             @RequestParam(name ="indexStatus") Integer indexStatus) {
        model.addAttribute("statement", statement);
        model.addAttribute("indexStatus", indexStatus);
        return "redirect:" + "/statement/status";
    }

html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">

<head th:replace="fragments/head :: headFragment (pageTitle='Заявления')">
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
</head>
<body>  
    <div class="sticky-top" th:insert="fragments/header :: fragment_header"></div>
    
    <form id="statusForm" th:action="@{/statement/status/save}" th:object="${statement}" method="post">
        
        <input type="text" th:value="${indexStatus}">
    
        <input type="text" th:field="*{statusList[__${indexStatus}__].id}">
        <input type="text" th:field="*{statusList[__${indexStatus}__].statement.id}">
        <input hidden="true" type="text" th:field="*{statusList[__${indexStatus}__].user.id}">
        <input hidden="true" type="text" th:field="*{statusList[__${indexStatus}__].dForm}" th:value="${#dates.format(statement.statusList[__${indexStatus}__].dForm, 'dd.MM.yyyy HH:mm:ss')}">
        <input hidden="true" type="text" th:field="*{statusList[__${indexStatus}__].dChange}"   th:value="${#dates.format(statement.statusList[__${indexStatus}__].dChange, 'dd.MM.yyyy HH:mm:ss')}">
        <input hidden="true" type="text" th:field="*{statusList[__${indexStatus}__].pa}">
    
        <div class="container">
            <div class="d-flex justify-content-around">
                <button type="submit" class="btn btn-primary cancel_button col-5" id="cancelStatus" name="cancelStatus">
                    <img th:src="@{/img/icon/icon_left_arrow.png}" height="24">&nbsp;&nbsp;Назад
                </button>
                <button type="submit" class="btn btn-primary save_button col-5" id="saveStatus" name="saveStatus">
                    <img th:src="@{/img/icon/label_save.png}" height="24">&nbsp;&nbsp;Сохранить
                </button>
            </div>
            
            <div class="row mt-1 justify-content-center">               
                <label class="col-2 col-form-label bold">Статус</label>
                <select class="col-8 custom-select selectpicker" id="status" 
                        th:onchange="selectText(status, nameStatus); selectValue(status, codeStatus);">
                    <option th:if="${statement.statusList[__${indexStatus}__].statusType.id == null}" value="0"></option>
                    <option th:each="t : ${statusTypeList}"
                            th:value="${t.id}" th:text="${t.name}"
                            th:selected="${t.id == statement.statusList[__${indexStatus}__].statusType.id}"></option>
                </select>
                <input type="text" class="col-1" id="codeStatus" th:field="*{statusList[__${indexStatus}__].statusType.id}">
                <input type="text" class="col-1" id="nameStatus" th:field="*{statusList[__${indexStatus}__].statusType.name}">
            </div>
            
            
            <div class="row mt-2 justify-content-center">
                <label class="col-2 col-form-label bold">Дата</label>
                <input type="text" class="col-8 form-control date-element"
                        th:field="*{statusList[__${indexStatus}__].dateStatus}" onfocus="clearStyle(this);"
                        th:value="${#dates.format(statement.statusList[__${indexStatus}__].dateStatus, 'dd.MM.yyyy')}"
                        onkeypress="return keypress(event);" onkeydown="keydown(this, event);" onkeyup="keyup(this, event);" maxlength="10" 
                        id="dateStatus">
            </div>
            <div class="row mt-1 justify-content-center">
                <label class="col-2 col-form-label bold">Префикс</label>
                <input type="text" class="col-8 form-control" th:field="*{statusList[__${indexStatus}__].prefixOutNumber}" maxlength="10"
                     id="prefixOutNumber" onfocus="clearStyle(this);">
            </div>
            <div class="row mt-1 justify-content-center">
                <label class="col-2 col-form-label bold">Исх.№</label>
                <input type="text" class="col-8 form-control" th:field="*{statusList[__${indexStatus}__].outNumber}"  maxlength="50"
                     id="outNumber" onfocus="clearStyle(this);">
            </div>
            <div class="row mt-1 justify-content-center">
                <label class="col-2 col-form-label bold">Орган</label>
                <select class="col-8 custom-select selectpicker" id="statusOrgan" 
                        onchange="selectText(statusOrgan, statusNameOrgan); selectValue(statusOrgan, statusCodeOrgan); ">
                    <option value="0"></option>
                    <option th:each="o : ${organList}"
                            th:value="${o.id}" th:text="${o.name}"
                            th:selected="${statement.statusList[__${indexStatus}__].organ != null} ? ${o.id == statement.statusList[__${indexStatus}__].organ.id} : 'false'"></option>
                </select>
                <input hidden="true" type="text" class="col-3" id="statusCodeOrgan" th:field="*{statusList[__${indexStatus}__].organ.id}">
                <input hidden="true" type="text" class="col-2" id="statusNameOrgan" th:field="*{statusList[__${indexStatus}__].organ.name}">
            </div>
            <div class="row mt-1 justify-content-center">
                <label class="col-2 col-form-label bold">Заметка</label>
                <input type="text" class="col-8 form-control" th:field="*{statusList[__${indexStatus}__].note}" maxlength="255">
            </div>
        </div>
        
    </form>
    
    <div class="mb-5" th:insert="fragments/footer :: fragment_footer"></div>
    
    <script type="text/javascript">
        function selectValue(source, target) {
            target.value = source.options[source.selectedIndex].value;
        }
    </script>
    <script type="text/javascript">
        function selectText(source, target) {
            target.value = source.options[source.selectedIndex].text;
        }
    </script>
    
    
    
    <script type="text/javascript">
        function selectChange(select) {
            if (select.options[select.selectedIndex].value == 5) {
                document.getElementById('prefixOutNumber').value = 'исх.'
            }
        }
    </script>
    
    <!-- 
    
    <script type="text/javascript">
        window.addEventListener("load", function() {
            
        }, false);
    </script>
     -->
</body>
</html>

Кусок контроллера сохранения статуса

    @RequestMapping(value = "/statement/status/save", params = "saveStatus")
    public String saveStatus(HttpSession session,
                             Model model,
                             @ModelAttribute("statement") Statement statement,
                             @ModelAttribute("indexStatus") Integer indexStatus) {
        
        Sysdate sysdate = sysdateService.getSysdate();
        SecurityUserDetails userDetails = (SecurityUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        model.addAttribute("user", userDetails.getUser());
        
        Status status = statement.getStatusList().get(indexStatus);        
        status.setdChange(sysdate.getSysdate());                           
        status.setUser(userDetails.getUser());                            
        if (null != status.getOrgan()) {
            if ((null == status.getOrgan().getId()) || (0 == status.getOrgan().getId())) { 
                status.setOrgan(null);
            }
        }
        if (status.getId() == null) {                                      
            status.setdForm(sysdate.getSysdate());
            status.setPa(1);
        }
        System.out.println("******После сохранения******");
        for (Status s : statement.getStatusList()) {
            System.out.println("id=" + s.getId() + ", statusId: " + s.getStatusType().getId());
        }
        model.addAttribute("statement", statement);
        return "redirect:" + "/statement/edit";
    }

Помогите пожалуйста. Заранее спасибо за помощь. Причем это только касается idStatus. Их даты не меняются


Ответы (0 шт):