LazyInitializationException与太多表格 - 更好的模型?

时间:2012-07-11 14:45:21

标签: java hibernate jsf primefaces jboss7.x

两天了,我试图让我的JSF + Primefaces / JBoss AS 7.1 / Hibernate应用程序正常工作,我在LazyInitializationExceptionToo many tables; MySQL can only use 61 tables in a join错误之间来回反复。

我将尝试尽可能正确地描述我当前的实体模型。

我有一台由几个模块组成的机器。每个模块基本上都是我的Web应用程序中的一个选项卡,在此选项卡上,表单中有几个字段。问题出在下拉字段中。对于那些,我从drools系统外部获得可用选项,根据其他模块中的其他字段构建选项。例如。可用的颜色取决于所选的表面材质,并相应地创建下拉列表。

现在,由于JSF / Primefaces的限制,我需要将选定的下拉列值保存为模块实体中的对象。有关我的问题,请参阅CustomContent in Primefaces selectOneMenu without persisting objectDisabling items with PrimeFaces SelectOneMenu with custom content / p:column

因此,对于每个DropDown字段,我在模块实体类中都有@OneToOne关系:

@Entity
public class PressureModule {

    @OneToOne(cascade = CascadeType.ALL)
    private Machine                machine;

    @OneToOne(cascade = CascadeType.ALL)
    private DropDownSelectItem     type         = DropDownSelectItem.getSelectOneItem();

    @OneToOne(cascade = CascadeType.ALL)
    private DropDownSelectItem     pressureTop  = DropDownSelectItem.getSelectOneItem();

    @OneToOne(cascade = CascadeType.ALL)
    private DropDownSelectItem     color        = DropDownSelectItem.getSelectOneItem();

    // getters, setters
}

还有一个DopDownSelectItem:

@Entity
public class DropDownSelectItem implements Serializable, Comparable<DropDownSelectItem> {

    @Id
    @GeneratedValue
    private Long              id;
    @Column
    private String            label;
    @Column
    private String            value;
    @Column
    private boolean           disabled;
    @Column
    private String            disabledReason;
}

Hibernate会自动创建以下表格:

CREATE TABLE `dropdownselectitem` (
  `id` bigint(20) NOT NULL,
  `disabled` tinyint(1) default NULL,
  `disabledReason` varchar(255) default NULL,
  `label` varchar(255) default NULL,
  `value` varchar(255) default NULL,
  PRIMARY KEY  (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;


CREATE TABLE `pressuremodule` (
  `id` bigint(20) NOT NULL,
  `machine_id` bigint(20) default NULL,
  `pressuretop_id` bigint(20) default NULL,
  `color_id` bigint(20) default NULL,
  `type_id` bigint(20) default NULL,
  PRIMARY KEY  (`id`),
  CONSTRAINT `FK8E3D129AE7CE7BEF` FOREIGN KEY (`type_id`) REFERENCES `dropdownselectitem` (`id`),
  CONSTRAINT `FK8E3D129ABD1E6ED1` FOREIGN KEY (`pressuretop_id`) REFERENCES `dropdownselectitem` (`id`),
  CONSTRAINT `FK8E3D129ABD1EE330` FOREIGN KEY (`color_id`) REFERENCES `dropdownselectitem` (`id`),
  CONSTRAINT `FK8E3D129AC56471E2` FOREIGN KEY (`machine_id`) REFERENCES `machine` (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;

下拉列表中包含以下逻辑:

在.xhtml中:

<p:selectOneMenu value="#{bean.field}" var="x">
    <f:selectItems
        value="#{dropDownValuesBean.getSelectItems()}" var="dd"
        itemLabel="#{dd.label}" itemValue="#{dd}" />
    <p:column>
        <h:outputText value="#{x.label}" />
        <h:outputText value=" {#{x.value}}" />
    </p:column>
    <p:ajax event="change" update="@form" />
</p:selectOneMenu>

DropDownValuesBean(缩短):

public List<PstSelectItem> getSelectItems(final String module, final String field) {

    knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
    List<PstSelectItem> returnList;

    StatefulKnowledgeSession statefulKnowledgeSession = knowledgeBase.newStatefulKnowledgeSession();
    statefulKnowledgeSession.insert(sessionBean.getActiveMachine());
    statefulKnowledgeSession.fireAllRules();
    Collection<FactHandle> handles = statefulKnowledgeSession.getFactHandles(new ClassObjectFilter(DropDownSelectItem.class));
    for (FactHandle handle : handles) {
        DropDownSelectItem selectItem = (DropDownSelectItem) statefulKnowledgeSession.getObject(handle);
        returnList.add(selectItem);
    }
    Collections.sort(returnList);
    return returnList;
}

现在的问题是,如果我有很多下拉字段(我们说的是最多150个),则会发生以下异常:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Too many tables; MySQL can only use 61 tables in a join

原因很清楚,我能理解这个问题。现在,如果我将实体更改为使用@OneToOne( fetch = FetchType.LAZY),我会遇到着名的LazyInitializationException。这并不奇怪。

当我为此搜索解决方案时,我主要获得对Spring框架附带的OpenSessionInView过滤器的引用。由于我不使用Spring,因为我不计划引入这种依赖,所以我有点迷失。

我已经尝试过以下事项:

  • 在我的DAO中使用@PersistenceContext(type = PersistenceContextType.EXTENDED)https://community.jboss.org/thread/177735
  • 仅存储对数据库中所选dropDown值(仅选择String而不是整个对象)的引用 - 失败,因为我无法从实体中的String重新计算所选DropDownSelectItem,因为我无法注入相应的Drools逻辑进入实体(@Inject s)不支持@Entity
  • 直接将序列化的DropDownSelectItem保存在数据库中,但这导致了巨大的数据库表(因为每个DropDown项都保存在blob中),我无法通过简单的SQL获取所选值(需要用于报告)

环境:

  • JBoss AS 7.1.0
  • Primefaces 3.2
  • MySQL 5.5
  • JDK 6

有什么想法吗?如果需要更多关于配置或任何信息的信息,我很乐意提供这些信息!

0 个答案:

没有答案