我在ManyToMany
(注释ManyToMany)和WorkDay
Event
关系
WorkDay实体
@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表单
当我第一次按下带有运行图标的时钟时,表示&#34;创建活动并开始工作日&#34;在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);
}
在日志中我看到:
仅更新了附加框架。总是看起来很好..当前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)
答案 0 :(得分:5)
将CascadeType.ALL
中的CascadeType.MERGE
的{{1}}更改为events
使用此代码
WokrDay entity
而不是
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
请勿使用@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
,请使用ArrayList
。因为HashSet
允许重复。
有关CasecadeType的更多信息,请按照教程:
答案 1 :(得分:0)
我认为简单的解决方案是删除多对多关系中的级联并手动完成工作! 。无论如何,我看到你已经多余地做了这件事。所以尝试删除CascadeType.ALL
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
How to persist @ManyToMany relation - duplicate entry or detached entity