`
xfxlch
  • 浏览: 167651 次
  • 性别: 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----
分享到:
评论

相关推荐

    jpa性能优化ppt

    8. **选择正确的继承映射策略**:根据具体需求选择最合适的继承映射策略,如单表、每类一张表或每子类一张表。 9. **使用原生查询**:在必要时利用原生SQL查询,它们可以提供更高的灵活性和性能。 10. **利用...

    hibernate常见异常针对于jpa

    2. **属性继承:** 基类的属性将被子类继承并映射到数据库表中。 3. **注解限制:** 使用`@MappedSuperclass`注解的类不能同时使用`@Entity`或`@Table`注解。 **示例代码:** 假设有一个基类`BaseEntity`,其中包含...

    java基础ppt

    同步机制包括synchronized关键字、wait()、notify()和notifyAll()方法,防止并发访问共享资源引发的问题。 9. **泛型**: 泛型允许在类、接口和方法中使用类型参数,提高了代码的类型安全性和重用性。 10. **反射...

    struts2.0 spring2.5 hibernate3.2组合的jar包集合

    **Struts2.0** 是一个基于MVC设计模式的Web应用程序框架,它继承了Struts1的优点并解决了其存在的问题。Struts2的核心是Action类,它处理用户请求,并通过Result来呈现结果页面。此外,Struts2还支持OGNL(Object-...

    JAVA编程语言的计算机软件开发应用.zip

    Java语法简洁且严谨,它借鉴了C++的优点,同时去除了指针等易引发错误的元素,增强了程序的安全性。类和对象是面向对象编程的基础,Java通过封装、继承和多态性实现模块化设计,提高代码复用性和可维护性。接口则是...

    弹簧测试数据库

    3. **编写测试类**:继承Spring的`@RunWith(SpringRunner.class)`注解,声明`@SpringBootTest`或`@DataJpaTest`注解来启动Spring容器,并利用`@Transactional`注解确保每次测试都在独立的事务中运行,测试结束后自动...

    java

    - 线程同步:为了防止多个线程同时访问共享资源引发的问题,Java提供了synchronized关键字、wait/notify机制等同步手段。 6. **网络编程** - Socket编程:Java的Socket和ServerSocket类用于网络通信,实现客户端-...

    什么是Java EE 5

    然而,“J2EE”这一名称逐渐引发了混淆,因为它暗示了一套独立于Java主平台的技术体系。为了澄清这一点,并强调Java EE作为Java家族的一员,Sun Microsystems决定将J2EE 1.5更名为Java EE 5。 #### 架构与功能更新 ...

    SpringREST-API-TransactionHandle

    READ_COMMITTED可能导致脏读(一个事务读到另一个事务未提交的数据),而REPEATABLE_READ可以防止脏读,但可能引发不可重复读(同一个事务在不同时间读取同一数据,结果不同)。 7. **幂等性设计**:在RESTful API...

    JavaTutorial-master

    Java的语法与C++相似,但更加简化,避免了C++的一些容易引发错误的特性,如指针操作。Java应用程序可以在任何安装了Java虚拟机(JVM)的设备上运行,这使得Java成为开发跨平台应用的理想选择。 二、Java环境配置 在...

Global site tag (gtag.js) - Google Analytics