`
xfxlch
  • 浏览: 162519 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JPA 单表继承引发的问题.

 
阅读更多
背景:
我们有这么一个需求:我们的系统要求我们把页面展示的表格字段全部保存在数据库里,就是客户可以根据自己的需求来自定义自已想要看的那些字段,然后这部书数据就持久化到我们的数据库里。如果客户可以自定义一个grid_view(table):名字为view1, 那view1下会关联到不同的column(gridviewqueryItem表),同时我们也会把按照呐个字段group,filter, sort都持久化到这张表理去。这样就形成了一个一对多的关系,然后对于gridviewqueryitem表,我们就用了一个queryItemType字段来区别这条记录是columns还是group还是filter还是sort。然后当我们从GridView中取出这个columnList的时候,我们根据queryItemType的值来loop这个columnlist,并且分类得到groupsList,filterList还是SortList。 美国的同事看到这个代码,坚决说要重写,不能写的这么啰嗦。说可以利用JPA 的单表继承来做:single table inheritance。 虽然不情愿,但是还是得这么干。否则codeview不过关,代码checkin不了。

方案:
单表继承example:http://www.thejavageek.com/2014/05/14/jpa-single-table-inheritance-example/

原先我们的表结构设计师这样子的:
@Entity
public class GridView {
    @Id
    @GeneratedValue(generator = "GRID_VIEW_ID_SEQ", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "GRID_VIEW_ID_SEQ", sequenceName = "GRID_GENERIC_ID_SEQ", allocationSize = 1)
    private Long id;

    @Column(name = "GRID_CONFIG_ID")
    private Long gridId;

    @Column(name = "NAME")
    private String name;

    @ManyToOne
    @JoinColumn(name = "USER_ID")
    private User user;

    @OneToMany(mappedBy = "gridView", fetch = FetchType.EAGER, cascade =  CascadeType.ALL )
    private List<GridViewQueryItem> gvqiList;



后来就改成了这样:
@Entity
public class GridView {
    @Id
    @GeneratedValue(generator = "GRID_VIEW_ID_SEQ", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "GRID_VIEW_ID_SEQ", sequenceName = "GRID_GENERIC_ID_SEQ", allocationSize = 1)
    private Long id;

    @Column(name = "GRID_CONFIG_ID")
    private Long gridId;

    @Column(name = "NAME")
    private String name;

    @ManyToOne
    @JoinColumn(name = "USER_ID")
    private User user;


    @OneToMany(mappedBy = "gridViewCol", fetch = FetchType.EAGER, cascade =  CascadeType.ALL, orphanRemoval = true)
    @Where(clause="QUERY_ITEM_TYPE='columns'")
    private List<GridViewQueryItemColumns> gvqiColumns;
    
    @OneToMany(mappedBy = "gridViewSort", fetch = FetchType.EAGER, cascade =  CascadeType.ALL, orphanRemoval = true )
    @Where(clause="QUERY_ITEM_TYPE='sorts'")
    private List<GridViewQueryItemSorts> gvqiSorts;
    
    @OneToMany(mappedBy = "gridViewFilter", fetch = FetchType.EAGER, cascade =  CascadeType.ALL, orphanRemoval = true )
    @Where(clause="QUERY_ITEM_TYPE='filters'")
    private List<GridViewQueryItemFilters> gvqiFilters;
    
    @OneToMany(mappedBy = "gridViewGroup", fetch = FetchType.EAGER, cascade =  CascadeType.ALL, orphanRemoval = true )
    @Where(clause="QUERY_ITEM_TYPE='groups'")
    private List<GridViewQueryItemGroups> gvqiGroups;


主要这里的Where语句刚开始是没有的,在没有Where条件的情况下,我的项目做save操作的时候,能够成功,但是作查询的时候,就出异常了。

原本按我们之前的理解是JPA会自动根据查询出来的queryItemType的值,来匹配到对应的List上,比如:queryItemType=columns,那么当我们拿到查询结果的时候,columns相关的数据就会自动封装到gvqiColumns 这个集合里去,但是事实却没有,它把所有的数据全部都整合到一个gvqiColumns的集合里去了,然后我们要取里面的数据时候,就是抛WrongClassException的异常。

后来google大神帮我解决了这个问题:
http://stackoverflow.com/questions/13972633/jpa-mapping-for-one-to-many-with-inheritance-mapping
就是加了Where语句,并且记住了clause里的String字符串是"QUERY_ITEM_TYPE='groups'",不要忘记了单引号:)

其实在解决了这个问题之后,又有了其他的问题。
比如我想更新gridview下面的columns等信息的时候,一直更新不成功,它只会新增新的column,但是我要的是删除之前的,再插入新的。但是老是不成功,后来就加了orphanRemoval = true

但是还是不行,错误提示:
引用
A collection with cascade=“all-delete-orphan” was no longer referenced by the owning entity instance


后来google了这个链接:
http://stackoverflow.com/questions/9430640/a-collection-with-cascade-all-delete-orphan-was-no-longer-referenced-by-the-ow


然后通过
if(CollectionUtils.isEmpty(gridView.getGvqiColumns())) {//save
    		gridView.setGvqiColumns(gvqiColumns);
    	} else { //update 
    		[color=red]gridView.getGvqiColumns().clear();
    		gridView.getGvqiColumns().addAll(gvqiColumns);[/color]
    	}

标红的两行代码解决了update的问题。

记录的比较零散。。。权且给自己做个笔记吧
----EOF----
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics