避免在 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 SavedDateboolean initialNoteboolean noteModifiedboolean 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 维护租户数据隔离?

如何在 Spring Cloud Data Flow 中为 Spring Batch 作业设置调度程序?

看了一下unity5.6的新功能 以及Timeline

unity过场动画组件Timeline

使用spring-cloud-zuul-rate-limit在zuul中为服务限流