2日間、JSF + Primefaces / JBoss AS 7.1 / Hibernateアプリケーションを機能させようとしていますが、LazyInitializationException
sとToo many tables; MySQL can only use 61 tables in a join
エラーの間を行き来しています。
現在のエンティティ モデルをできるだけ正確に説明しようと思います。
複数のモジュールで構成されるマシンがあります。すべてのモジュールは基本的に私の Web アプリケーションのタブであり、このタブにはフォームにいくつかのフィールドがあります。問題はドロップダウン フィールドにあります。それらについては、他のモジュールの他のフィールドに応じて、オプションを構築する drools システムから外部で利用可能なオプションを取得します。たとえば、使用可能な色は選択した表面の素材によって異なり、それに応じてドロップダウンが作成されます。
ここで、JSF/Primefaces の制限により、選択したドロップダウン値をオブジェクトとしてモジュール エンティティに保存する必要があります。私が持っていた/持っている質問については、オブジェクトを永続化せずに Primefaces selectOneMenu の CustomContent を参照してください。
したがって、すべての 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
. これは驚くべきことではありません。
これに対する解決策を検索すると、ほとんどの場合OpenSessionInView
、Spring フレームワークに付属するフィルターへの参照が得られます。私はSpringを使用しておらず、その依存関係を導入する予定がないため、少し迷っています。
私はすでに次のことを試しました:
- DAO での使用
@PersistenceContext(type = PersistenceContextType.EXTENDED)
: https://community.jboss.org/thread/177735 - 選択した dropDown 値 (オブジェクト全体ではなく、選択した文字列のみ) への参照のみをデータベースに保存します
DropDownSelectItem
。エンティティにそれぞれの Drools ロジックを挿入できないため、エンティティでその文字列から選択したものを再計算できないため、これは失敗します。 (@Inject
ing は@Entity
s ではサポートされていません) - シリアル化された DropDownSelectItem をデータベースに直接保存しますが、それは巨大なデータベース テーブルにつながり (すべての DropDown-item が blob に保存されるため)、単純な SQL (レポート目的で必要) で選択された値を取得できません。
環境:
- JBoss AS 7.1.0
- プライムフェイス 3.2
- MySQL 5.5
- JDK6
何か案は?構成などに関する詳細情報が必要な場合は、喜んで提供します。