source

Jpa - Hibernate ManyToMany 많은 사람들이 조인 테이블에 삽입합니다.

nicesource 2023. 10. 16. 21:55
반응형

Jpa - Hibernate ManyToMany 많은 사람들이 조인 테이블에 삽입합니다.

나는 다음을 가지고 있습니다.ManyToMany사이의 관계WorkDay( 주석 ManyToMany가 있음) 및Event

워크데이엔티

@Entity
@Table(name = "WORK_DAY", uniqueConstraints = { @UniqueConstraint(columnNames = { "WORKER_ID", "DAY_ID" }) })
@NamedQueries({
        @NamedQuery(name = WorkDay.GET_WORK_DAYS_BY_MONTH, query = "select wt from WorkDay wt where wt.worker = :worker and to_char(wt.day.day, 'yyyyMM') = :month) order by wt.day"),
        @NamedQuery(name = WorkDay.GET_WORK_DAY, query = "select wt from WorkDay wt where wt.worker = :worker and wt.day = :day") })
public class WorkDay extends SuperClass {

    private static final long serialVersionUID = 1L;

    public static final String GET_WORK_DAYS_BY_MONTH = "WorkTimeDAO.getWorkDaysByMonth";
    public static final String GET_WORK_DAY = "WorkTimeDAO.getWorkDay";

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "WORKER_ID", nullable = false)
    private Worker worker;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "DAY_ID", nullable = false)
    private Day day;

    @Column(name = "COMING_TIME")
    @Convert(converter = LocalDateTimeAttributeConverter.class)
    private LocalDateTime comingTime;

    @Column(name = "OUT_TIME")
    @Convert(converter = LocalDateTimeAttributeConverter.class)
    private LocalDateTime outTime;

    @Enumerated(EnumType.STRING)
    @Column(name = "STATE", length = 16, nullable = false)
    private WorkDayState state = WorkDayState.NO_WORK;

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "WORK_DAY_EVENT", joinColumns = {
            @JoinColumn(name = "WORK_DAY_ID", nullable = false)}, inverseJoinColumns = {
            @JoinColumn(name = "EVENT_ID", nullable = false)})
    @OrderBy(value = "startTime desc")
    private List<Event> events = new ArrayList<>();

    protected WorkDay() {
    }

    public WorkDay(Worker worker, Day day) {
        this.worker = worker;
        this.day = day;
        this.state = WorkDayState.NO_WORK;
    }
}

이벤트실체

@Entity
@Table(name = "EVENT")
public class Event extends SuperClass {

    @Column(name = "DAY", nullable = false)
    @Convert(converter = LocalDateAttributeConverter.class)
    private LocalDate day;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TYPE_ID", nullable = false)
    private EventType type;

    @Column(name = "TITLE", nullable = false, length = 128)
    private String title;

    @Column(name = "DESCRIPTION", nullable = true, length = 512)
    private String description;

    @Column(name = "START_TIME", nullable = false)
    @Convert(converter = LocalDateTimeAttributeConverter.class)
    private LocalDateTime startTime;

    @Column(name = "END_TIME", nullable = true)
    @Convert(converter = LocalDateTimeAttributeConverter.class)
    private LocalDateTime endTime;

    @Enumerated(EnumType.STRING)
    @Column(name = "STATE", nullable = false, length = 16)
    private EventState state;

    protected Event() {
    }
}

명확화를 위한 UI 양식 첨부

enter image description here

Clock with run 아이콘을 처음 누르면 빈에서 "이벤트 생성 및 업무 시작"을 의미하며 다음 메서드를 호출합니다.

public void startEvent() {
    stopLastActiveEvent();
    Event creationEvent = new Event(workDay.getDay().getDay(), selectedEventType, selectedEventType.getTitle(),
            LocalDateTime.now());
    String addEventMessage = workDay.addEvent(creationEvent);
    if (Objects.equals(addEventMessage, "")) {
        em.persist(creationEvent);
        if (workDay.isNoWork()
                && !creationEvent.getType().getCategory().equals(EventCategory.NOT_INFLUENCE_ON_WORKED_TIME)) {
            startWork();
        }
        em.merge(workDay);
    } else {
        Notification.warn("Невозможно создать событие", addEventMessage);
    }
    cleanAfterCreation();
}

public String addEvent(Event additionEvent) {
    if (!additionEvent.getType().getCategory().equals(NOT_INFLUENCE_ON_WORKED_TIME)
            && isPossibleTimeBoundaryForEvent(additionEvent.getStartTime(), additionEvent.getEndTime())) {
        events.add(additionEvent);
        changeTimeBy(additionEvent);
    } else {
        return "Пересечение временых интервалов у событий";
    }
    Collections.sort(events, new EventComparator());
    return "";
}

private void startWork() {
    workDay.setComingTime(workDay.getLastWorkEvent().getStartTime());
    workDay.setState(WorkDayState.WORKING);
}

로그인 정보 보기:

  1. 이벤트 테이블에 삽입
  2. 업데이트 work_day table
  3. work_day_event 테이블에 삽입

UI에서 첨부된 프레임만 업데이트했습니다.항상 괜찮아보이네요..현재의WorkDay객체는 하나의 요소를 가지고 있습니다.eventscollection, 또한 모든 데이터가 에 삽입됩니다.DB.. 그러나 이번에 이벤트 행을 편집하는 경우

enter image description here

이벤트 행 수신기:

public void onRowEdit(RowEditEvent event) {
    Event editableEvent = (Event) event.getObject();
    LocalDateTime startTime = fixDate(editableEvent.getStartTime(), editableEvent.getDay());
    LocalDateTime endTime = fixDate(editableEvent.getEndTime(), editableEvent.getDay());
    if (editableEvent.getState().equals(END) && startTime.isAfter(endTime)) {
        Notification.warn("Невозможно сохранить изменения", "Время окончания события больше времени начала");
        refreshEvent(editableEvent);
        return;
    }
    if (workDay.isPossibleTimeBoundaryForEvent(startTime, endTime)) {
        editableEvent.setStartTime(startTime);
        editableEvent.setEndTime(endTime);
        workDay.changeTimeBy(editableEvent);
        em.merge(workDay);
        em.merge(editableEvent);
    } else {
        refreshEvent(editableEvent);
        Notification.warn("Невозможно сохранить изменения", "Пересечение временых интервалов у событий");
    }
}

에게work_day_event새 행을 같은 행에 삽입work_day_id그리고.event_iddata. 그리고 edit row가 다른 경우에 삽입 등을 한번 더 합니다.결과적으로 나는 몇개의 같은 행을 가지고 있습니다.work_day_event테이블. 왜 이런 일이 일어날까요?

github 프로젝트 저장소 링크(ver-1.1.0-many-to-many-problem 분기 보기)

enter image description here

바꾸다CascadeType.ALL로.CascadeType.MERGE위해서events에서WorkDay entity

이 코드 사용

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)

대신에

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)

사용하지않음ArrayList,사용하다HashSet.왜냐면ArrayList중복을 허용합니다.

Casecade에 대한 자세한 정보자습서를 따라 입력합니다.

  1. 동면 JPA 캐스케이드 유형
  2. 캐스케이드 모범 사례

간단한 해결책은 많은 관계에서 캐스케이드를 제거하고 수동으로 일을 하는 것이라고 생각합니다!어쨌든 이미 중복해서 하시는 것을 봅니다.CascadeType을 제거해 보십시오.ALL

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)

@ManyToMany 관계를 유지하는 방법 - 중복 항목 또는 분리된 엔티티

언급URL : https://stackoverflow.com/questions/36812689/jpa-hibernate-manytomany-do-many-insert-into-join-table

반응형