我遵循WorkDay(具有注释ManyToMany)和Event之间的ManyToMany关系
WorkDay entity
@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; } }
Event entity
@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",length = 16) private EventState state; protected Event() { } }
为了清晰起见,附加的UI表单
当我第一次按下带有运行图标的Clock时,它意味着在bean中创建“创建事件并开始工作日”,调用以下方法:
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); }
在日志中我看到:
>插入事件表
>更新work_day表
>插入work_day_event表
在UI上更新仅附加框架.总是看起来很好..当前的WorkDay对象在events集合中有一个元素,也将所有数据都插入到DB ..但是如果这次编辑事件行
事件行侦听器:
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_id数据的新行.并且如果编辑行,则执行一次插入等操作.在结果中,我在work_day_event表中有几个等于行.为什么会这样?
link to github project repository(look ver-1.1.0-many-to-many-problem branch)
对于WokrDay实体中的事件,将CascadeType.ALL更改为CascadeType.MERGE
使用此代码
@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
代替
@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
不要使用ArrayList,使用HashSet.因为ArrayList允许重复.
有关CasecadeType的更多信息,请按照教程: