2016-04-23 8 views
8

に参加WorkDayManyToManyの関係を次の(注釈多対多を持っている)とEventJPA - Hibernateは多対多の中に多くの挿入を行い、私が持っているテーブル

平日エンティティ

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

明快

enter image description here

のための付属UIフォームIは、実行アイコン初めてで時計を押すと、それは以下のメソッドを呼び出す、「イベントを作成し、作業日スタート」豆を意味する:

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テーブル
  3. work_day_eventテーブルにUIを更新のみ取り付けられたフレームに

を挿入します。常に細かい..現在WorkDayオブジェクトもすべてのデータがDBに挿入されeventsコレクション内の1つの要素を持っている..しかし、ルックス今回編集イベント行

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_idevent_idのデータで挿入します。そして、他の行を編集する場合は、もう一つ挿入してください。結果では、私はwork_day_eventテーブルにいくつかの等しい行を持っています。なぜこれが起こるのですか?

link to github project repository(look ver-1.1.0-many-to-many-problem branch)

enter image description here

+0

あなたは仕事の日にイベントのために 'CascadeType.ALL'を持っています。つまり、イベント自体を個別に保存する必要はありません。作業日を保存することは、仕事をするべきです: 'em.merge(workDay);'。 –

+0

@XtremeBiker、はい、それは私の問題を解決していません – HAYMbl4

+0

work_day_eventに別のマッパーエンティティクラスを使用しようとしましたか? –

答えて

0

私は簡単な解決策は、多くの関係に多くの上のカスケードを削除し、ジョブを手動で行うことだと思います! 。とにかくあなたはすでにそれを重複してやっているのが分かります。 CascadeTypeを削除してみてください。WokrDay entity

使用中のeventsためCascadeType.MERGEにALL

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

How to persist @ManyToMany relation - duplicate entry or detached entity

3

変更CascadeType.ALLこのコード

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

代わりの

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

HashSetを使用し、ArrayListを使用しないでください。 ArrayListは重複を許可するためです。

CasecadeTypeについての詳細情報については、チュートリアルに従ってください:

  1. Hibernate JPA Cascade Types
  2. Cascading best practices
+0

です。私は 'CascadeType.ALL'の代わりに' CascadeType.MERGE'を使用しようとしましたが、 'Set'を使用しようとしましたが、私の問題は解決しませんでした。 – HAYMbl4

+0

@ HAYMbl4可能であれば、githubを通してプロジェクトを共有することができます。あなたの問題を解決しようとします。 – SkyWalker

+0

@ HAYMbl4より理解を深めるため、http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/をご覧ください。 – SkyWalker

関連する問題