I am working on a Spring-MVC project, for which I am working currently on Timeline functionality. I have a basic infrastructure already in progress, but currently, I am dealing with mappings, and how to avoid creating duplicates for the Timeline functionality.
Situation :
In our tool, there is GroupSection which has a one-to-many mapping with GroupNote. GroupNote object has a one-to-many mapping with Attachments, History.
What is this timeline functionality?
In timeline functionality, any User can jump at any point in time and check how the contents of GroupSection, GroupNotes, attachments and History.
How am I planning to implement it?
I have 4 variables in each of the above objects for handling this. They are Date SavedDate
, boolean initialNote
, boolean noteModified
, boolean latestNote
.
Along with that, each GroupNote has a self-join, will explain it soon.
Now, every time a Note is modified, the modified flag is set to true. In the night, I run a method, which checks for all modified objects, and only if the object is modified, it creates a duplicate instance for the Object, puts the new Date in it, marks it as the latest one, and persists it.
This way, I can load all the objects for a given date. And for normal daily usage, all notes which are marked as latest
, will be loaded.
Whenever a new Object is created for persistence, it is self-joined with the old object, with Cascade.Remove
. What this does is, if the user goes back and removes the object from 2015, then all subsequent objects till present are removed as well. This gives a time like behaviour.
Problem :
Now, if a GroupSection is modified, then I will create an instance of GroupSection and persist it, by copying properties from the modified GroupSection, and mark it as the latest.
Now, the Notes which that GroupSection was holding were not modified, but if I don't create its duplicate entries, then I won't see any Notes loaded in front-end. But I would like to avoid this. How can I do that?
Code finally :
GroupSection model :
@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 model :
@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();
}
The above DAO methods give me the modified sections from yesterday, or the last modified sections, and similarly Sections for given date. I have similar methods in 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();
}
I hope the question is understandable. If there is any doubt, kindly let me know.
Edit
One strategy I can think of is going with many-to-many mappings between GroupSection and GroupNotes. Unfortunately, a lot of backend as well as front-end code is already developed with a one-to-many mapping between GroupSection and GroupNotes. Still, I did add many-to-many mappings, but data-set is not getting loaded, also it is increasing the complexity a lot, a question in progress here. I would still prefer some other option.