避免在 Spring 中为 TImeline 功能创建重复项
Posted
技术标签:
【中文标题】避免在 Spring 中为 TImeline 功能创建重复项【英文标题】:Avoiding creating duplicates for TImeline functionality in Spring 【发布时间】:2016-06-13 16:10:35 【问题描述】:我正在开发一个 Spring-MVC 项目,我目前正在为此开发 Timeline 功能。我的基础架构已经在进行中,但目前我正在处理映射,以及如何避免为时间轴功能创建重复项。
情况:
在我们的工具中,GroupSection 与 GroupNote 具有一对多的映射关系。 GroupNote 对象与附件、历史记录具有一对多的映射关系。
这个时间线功能是什么?
在时间轴功能中,任何用户都可以在任何时间点跳转并查看 GroupSection、GroupNotes、附件和历史记录的内容。
我打算如何实施它?
我在上述每个对象中都有 4 个变量来处理这个问题。它们是Date SavedDate
、boolean initialNote
、boolean noteModified
、boolean latestNote
。
除此之外,每个GroupNote都有一个self-join,稍后会解释。
现在,每次修改注释时,修改标志都会设置为 true。晚上,我运行一个方法,它检查所有修改的对象,只有当对象被修改时,它才会为该对象创建一个重复的实例,将新的日期放入其中,将其标记为最新的,并将其持久化.
这样,我可以加载给定日期的所有对象。对于正常的日常使用,所有标记为latest
的笔记都会被加载。
每当为持久性创建新对象时,它都会与旧对象自联接,Cascade.Remove
。这样做的目的是,如果用户返回并从 2015 年删除该对象,那么直到当前的所有后续对象也将被删除。这给出了类似时间的行为。
问题:
现在,如果 GroupSection 被修改,那么我将创建一个 GroupSection 实例并通过从修改后的 GroupSection 复制属性来持久化它,并将其标记为最新。
现在,GroupSection 持有的 Notes 没有被修改,但如果我不创建它的重复条目,那么我将看不到前端加载的任何 Notes。但我想避免这种情况。我该怎么做?
代码终于:
GroupSection 模型:
@Entity
@Table(name = "membersection")
public class GroupSection
@Column(name = "section_save_date", columnDefinition = "date")
private Date secnSavedDate;
@Column(name = "initial_section", columnDefinition = "boolean default true")
private boolean initialSection;
@Column(name = "section_modified", columnDefinition = "boolean default false")
private boolean sectionModified;
@Column(name = "latest_section", columnDefinition = "boolean default false")
private boolean latestSection;
@JsonIgnore
@ManyToOne
@JoinColumn(name = "owned_section_id", nullable = true)
private GroupSection primarySection;
@OneToMany(mappedBy = "primarySection", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private Set<GroupSection> groupSectionSet = new HashSet<>();
@OneToMany(mappedBy = "ownednotes", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupNotes> sectionsnotes = new HashSet<>();
GroupNotes 模型:
@Entity
@Table(name = "groupnotes")
public class GroupNotes implements Serializable
@Column(name = "note_save_date", columnDefinition = "date")
private Date noteSavedDate;
@Column(name = "initial_note", columnDefinition = "boolean default true")
private boolean initialNote;
@Column(name = "note_modified", columnDefinition = "boolean default false")
private boolean noteModified;
@Column(name = "latest_note", columnDefinition = "boolean default false")
private boolean latestNote;
@JsonIgnore
@ManyToOne
@JoinColumn(name = "owned_note_id", nullable = true)
private GroupNotes primaryNote;
@OneToMany(mappedBy = "primaryNote", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private Set<GroupNotes> groupNotesSet = new HashSet<>();
GroupSectionDAOImpl :
@Override
@Transactional(readOnly = true)
public List<GroupSection> listGroupSectionByCanvasAndDate(int mcanvasid, Date dateToLoad)
Session session = this.sessionFactory.getCurrentSession();
org.hibernate.Query query = session.createQuery("From GroupSection as msection where " +
"msection.currentcanvas.mcanvasid=:mcanvasid and " +
"msection.secnSavedDate>:dateToLoad " +
" and msection.sectionDisabled=false and msection.latestSection=true and msection.sectionInActive=false order by msection.secnSavedDate asc");
query.setParameter("mcanvasid", mcanvasid);
query.setParameter("dateToLoad",dateToLoad);
return query.list();
@Override
public List<GroupSection> listModifiedSectionsForYesterday()
Session session = this.sessionFactory.getCurrentSession();
Calendar cal = Calendar.getInstance();
Query query = session.createQuery("from GroupSection as gs where gs.sectionModified=true and gs.latestSection=true and gs.secnSavedDate<:loadDate order by gs.secnSavedDate asc");
query.setParameter("loadDate",cal.getTime());
return query.list();
上述 DAO 方法为我提供了昨天修改的部分,或最后修改的部分,以及给定日期的类似部分。我在 GroupNotesDAOImpl 中有类似的方法
GroupSectionServiceImpl :
@Override
public List<GroupSection> retrieveModifiedSections()
List<GroupSection> groupSectionList = this.groupSectionDAO.listModifiedSectionsForYesterday();
for (GroupSection yesterdaySection : groupSectionList)
yesterdaySection.setLatestSection(false);
this.groupSectionDAO.updateGroupSection(yesterdaySection);
GroupSection newDaySection = new GroupSection();
BeanUtils.copyProperties(yesterdaySection, newDaySection);
newDaySection.setInitialSection(false);
newDaySection.setSectionModified(false);
newDaySection.setLatestSection(true);
newDaySection.setMsectionid(0);
newDaySection.setSortedSectionSet(null);
newDaySection.setSecnSavedDate(Calendar.getInstance().getTime());
int sectionSavedId = directAddGroupSection(newDaySection, yesterdaySection.getCurrentCanvasId());
List<GroupNotes> groupNotesList = this.groupNotesService.directListGroupNotesBySectionIdForCanvasCopying(yesterdaySection.getMsectionid());
for(GroupNotes groupNotes : groupNotesList)
Problem --> // No option but to create duplicates.
return this.groupSectionDAO.listModifiedSectionsForYesterday();
我希望这个问题是可以理解的。如果有任何疑问,请告诉我。
编辑
我能想到的一种策略是在 GroupSection 和 GroupNotes 之间进行多对多映射。不幸的是,许多后端和前端代码已经在 GroupSection 和 GroupNotes 之间使用一对多映射进行开发。 尽管如此,我确实添加了多对多映射,但数据集没有被加载,而且它也增加了很多复杂性,一个正在进行的问题here。我仍然更喜欢其他选择。
【问题讨论】:
hm.... 分离实体,将 id 设置为 null,进行必要的更改并像这里描述的那样持久化呢? ***.com/questions/11625096/cloning-jpa-entity @MaximS.Ivanov :这只是在创建一个副本,这是我想明确避免的问题。 【参考方案1】:我不确定我应该如何触发此删除功能。 对我来说,一个可行的策略是遵循一对多的关系 历史的 GroupSection(历史链中第一个被删除的)到相关的 GroupNotes。这种关系需要识别每个受影响的 GroupNotes 相应的历史实例并导致删除该实例。
在处理 GroupSections 时,您可能需要收集对这些 GroupNotes 的引用(我假设随着时间的推移,这个集合可能会发生变化) 并在最后清理结果集以避免反复检查 GroupNotes。
【讨论】:
【参考方案2】:我建议将 GroupSection 和 GroupNotes 之间的关联更改为多对多,以避免重复的 groupnotes。
@Entity
@Table(name = "membersection")
public class GroupSection
@Column(name = "section_save_date", columnDefinition = "date")
private Date secnSavedDate;
@Column(name = "initial_section", columnDefinition = "boolean default true")
private boolean initialSection;
@Column(name = "section_modified", columnDefinition = "boolean default false")
private boolean sectionModified;
@Column(name = "latest_section", columnDefinition = "boolean default false")
private boolean latestSection;
@JsonIgnore
@ManyToOne
@JoinColumn(name = "owned_section_id", nullable = true)
private GroupSection primarySection;
@OneToMany(mappedBy = "primarySection", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private Set<GroupSection> groupSectionSet = new HashSet<>();
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "groupsection_groupnote", joinColumns =
@JoinColumn(name = "GROUP_SECTION_ID", nullable = false, updatable = false) ,
inverseJoinColumns = @JoinColumn(name = "GROUP_NOTE_ID",
nullable = false, updatable = false) )
@JsonIgnore
private Set<GroupNotes> sectionsnotes = new HashSet<>();
GroupSectionServiceImpl :
@Override
public List<GroupSection> retrieveModifiedSections()
List<GroupSection> groupSectionList = this.groupSectionDAO.listModifiedSectionsForYesterday();
for (GroupSection yesterdaySection : groupSectionList)
yesterdaySection.setLatestSection(false);
this.groupSectionDAO.updateGroupSection(yesterdaySection);
GroupSection newDaySection = new GroupSection();
BeanUtils.copyProperties(yesterdaySection, newDaySection);
newDaySection.setInitialSection(false);
newDaySection.setSectionModified(false);
newDaySection.setLatestSection(true);
newDaySection.setMsectionid(0);
newDaySection.setSortedSectionSet(null);
newDaySection.setSecnSavedDate(Calendar.getInstance().getTime());
int sectionSavedId = directAddGroupSection(newDaySection, yesterdaySection.getCurrentCanvasId());
List<GroupNotes> groupNotesList = this.groupNotesService.directListGroupNotesBySectionIdForCanvasCopying(yesterdaySection.getMsectionid());
newDaySection.setGroupNotesSet(groupNotesList);
return this.groupSectionDAO.listModifiedSectionsForYesterday();
【讨论】:
【参考方案3】:使用@ManyToOne for GroupNote -> GroupSection,而不是在 GroupSection 中引用 GroupNote 怎么样?
当需要修改任何 GroupSection 时,您只需更新 GroupSection 及其修改日期即可。如果您希望 GroupNote 也被更新,您可以在服务级别通过单独的查询进行处理。
【讨论】:
【参考方案4】:我认为你应该试试这个想法。
@ManyToOne for GroupNote -> GroupSection,而不是在 GroupSection 中引用 GroupNote?
【讨论】:
以上是关于避免在 Spring 中为 TImeline 功能创建重复项的主要内容,如果未能解决你的问题,请参考以下文章
使用Chrome DevTools的Timeline分析页面性能
我们如何在 Spring cloud dataflow kafka binder 中为 Kafka 维护租户数据隔离?