私はかなり単純な問題を抱えていると思いますが、Hibernate を使用したクラスの適切な構造を思いついたり、ベスト プラクティスの例を見つけることができませんでした。
マップされたクラス Test を持つ 1 つのテーブル テストがあります。Bean によって制御される 1 つのページでは、管理編集用のリスト (AdminTest) にすべてのアイテムがあり、別のページには同じアイテムがリストされていますが、ラジオボタンのようなものを持つ通常のユーザーは、変更せずにそれらに影響を与えます (ShowTest)。データベース。
Hibernate は、addEntity 関数 (私のクラスでは Manager で終わる) を使用してアイテムを取得するときに、直接マップされたクラスを指定するように要求しているように見えるので、次のようなことを強制されているように感じます。
class Test { ... }
class AdminTest extends Test { ... }
@ManagedBean
class AdminTestManager {
List<AdminTest> items;
}
class ShowTest extends Test { ... }
@ManagedBean
class ShowTestManager {
List<ShowTest> items;
}
次に、AdminTest と ShowTest の両方を、同じフィールドを持つ同じテーブルに個別にマッピングします。テーブル テストにフィールドを追加するたびに両方のマッピングを更新する必要があるため、これは非常に悪いことです。
ここで何かを見逃しているように感じます。実際には、テーブル テストにマップされた 1 つのテストだけが必要であり、かなり継承されたマッピングが必要ですが、それらには列や 1 対 1 でマップされたテーブルなどの識別子が必要です。
編集:
私が試した別の解決策は、テスト用に 1 つのマッピングを作成し、AdminTest と ShowTest でそのクラスを拡張することでしたが、リフレクションを使用してゲッターを拡張クラスにコピーしています。
編集2:
私が求めていることをよりよく説明するために、ここで「現実世界」のシナリオを提供します。入力フィールドを介して質問を入力できるページと、各項目ごとに「はい」または「いいえ」だけのラジオボタンでこれらの質問をリストする別のページを備えたクイズエンジンを作成したいとしましょう。
データベーステーブルは次のように作成されます。
CREATE TABLE question (id INT AUTO_iNCREMENT, text VARCHAR, correct_answer INT, primary key(id));
私が必要だと思うクラスは次のとおりです。
class Question {
private int id;
private String text;
private int correctAnswer;
// Getters and setters.
}
class EditQuestion extends Question {
void updateItem() { ... }
void removeItem() { ... }
}
@ManagedBean(name = "edit_quiz")
@ViewScoped
class EditQuestionManager {
List<EditQuestion> items;
void addItem() { ... }
void init() {
items = (ArrayList<EditQuestion>) HibernateUtil.getSessionFactory().getCurrentSession().createSQLQuery("SELECT * FROM question").addEntity(EditQuestion.class)
.list();
}
}
class AnswerQuestion extends Question {
int radioButtonValue;
// Getters and setters.
}
@ManagedBean(name = "take_quiz")
@ViewScoped
class AnswerQuestionManager {
List<AnswerQuestion> items;
void calculateResults() { ... }
void init() {
items = (ArrayList<AnswerQuestion>) HibernateUtil.getSessionFactory().getCurrentSession().createSQLQuery("SELECT * FROM question").addEntity(AnswerQuestion.class).list();
}
}
次に、たとえば、クイズを表示する JSF ページは次のようになります。
<ui:repeat value="#{take_quiz.items}" var="question">
<div>#{question.text}</div>
<h:selectOneRadio value="#{question.radioButtonValue}" onchange="submit()">
<f:selectItem itemValue="1" itemLabel="Yes" />
<f:selectItem itemValue="0" itemLabel="No" />
</h:selectOneRadio>
</ui:repeat>
<h:commandLink action="#{take_quiz.calculateResults()}">Done</h:commandLink>
少なくとも私には見える問題は、管理ビューとユーザー ビューの両方に対してこの種のリストを作成するには、テーブル「質問」を AnswerQuestion と EditQuestion の両方にマップするエントリを作成する必要があることです。 hbm.xml ファイル。少なくともリフレクションを使用しないと (すべての getter 値を Question から AnswerQuestion/EditQuestion の新しいインスタンスにコピーするために)、ハックのように感じますか? これはあまり複雑に見えないということですか?
解決策: クラスがマップされた Hibernate テーブル クラスを拡張する代わりに、単純にそれらの型のプライベート プロパティを追加しました。また、マネージャークラスでは、データベースからアイテムを取得した後、アイテムをループして、次のようにリストを設定します。
ArrayList<Question> tempItems = (ArrayList<Question>) HibernateUtil.getSessionFactory().getCurrentSession().createSQLQuery("SELECT * FROM question").addEntity(Question.class).list();
ArrayList<EditQuestion> items = ArrayList<EditQuestion>();
for(int i = 0; tempItems.size(); i++) {
EditQuestion item = new EditQuestion();
item.setQuestion(tempItems.get(i));
items.add(item);
}