11

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.

Community
  • 1
  • 1
We are Borg
  • 5,117
  • 17
  • 102
  • 225
  • hm.... what about detaching entity, setting id to null, doing required changes and persisting like described here? http://stackoverflow.com/questions/11625096/cloning-jpa-entity – ivanenok Mar 08 '16 at 06:00
  • @MaximS.Ivanov : That is just creating a duplicate, a problem I want to explicitly avoid. – We are Borg Mar 08 '16 at 08:52

4 Answers4

0

I'm not sure I got how this remove functionality should be triggered. To me a viable strategy would be to follow the one-to-many relation from the historic GroupSection (first to-be-deleted of the history chain) to the related GroupNotes. This relation needs to identify of each of the affected GroupNotes the corresponding historic instance and cause a delete of such instance.

You may need to collect references to those GroupNotes while working up the GroupSections (there coulod be changes in this set over time, I'd assume) and cleanup the resulting set at the end to avoid checking GroupNotes obver and over.

rpy
  • 3,953
  • 2
  • 20
  • 31
0

I suggest to change the association between GroupSection and GroupNotes to many-to-many to avoid duplicated 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();

    }
SEY_91
  • 1,615
  • 15
  • 26
0

How about having @ManyToOne for GroupNote -> GroupSection, instead of referring GroupNote in GroupSection?

When any GroupSection needs to be modified, you can just update GroupSection and its modification date. If you want GroupNote also to be updated, you can handle it at service level, by separate query.

kishor borate
  • 158
  • 1
  • 11
0

I think you should try this idea out.

@ManyToOne for GroupNote -> GroupSection, instead of referring GroupNote in GroupSection?