0

1つの単体テストで組み込みOpenEJBを使用しています。テストは機能しません。私がデバッグしているときに、怠惰なフェッチされたフィールドが特異に動作することがわかりました。

それは本当に可能ですか?フィールドがすでにロードされている場合、すべてが通常の方法で行われます。

//field == "something from db"
field = "ahoj";
//field == "ahoj"

ただし、フィールドがロードされていない場合:

//field == null
field = "ahoj";
//field == null

私が見たコールスタックでは、最上位にいくつかのレイヤーのメソッドがあり、おそらくエンティティがレイヤーを管理していることがわかりました。Googleを試しましたが、答えが見つかりませんでした。

だから私の質問は:管理対象エンティティのフェッチされていないフィールドを割り当てることができないというルールはありますか?同様のルールがある場合、データベースから取得せずにフィールドの値を変更するにはどうすればよいですか?

4

1 に答える 1

0

もちろん答えはイエスです。しかし、昨日何が起こっていたのでしょうか?

問題は永続コンテキストにあり、メソッド名にもある可能性があります。フィールドはそのセッターで更新されませんでした。永続コンテキストはトランザクションにバインドされています。したがって、複数のフィールドを更新して保存する必要がある場合は、1つのトランザクション内ですべての操作を実行する必要があります。トランザクションを開始し、エンティティでセッターを呼び出し、エンティティへのアクセスを管理するセッションBeanでupdateメソッドを呼び出す必要があります。

@Basic(fetch=FetchType.LAZY)
String field;

@Override
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public String getFiled() {
    return field;
}

@Override
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void setText(String text) {
    //other code
    this.field = text;
    //other code
}

ゲッターは、トランザクション内で呼び出される場合と呼び出されない場合があります。ただし、セッターは既存のトランザクション内で呼び出す必要があります。同じトランザクション属性がセッションBeanの更新メソッドに適用されます。さらにreattach()、適切な永続コンテキストでオブジェクトを操作していることを確認するためのメソッドが必要です。

@Stateless
class AccessBean implements Accessor {
    @PersistenceContext(unitName = "MyUnit")
    private EntityManager manager;

    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public TheEntity update(TheEntity e) {
        e = manager.merge(e);
        manager.flush();

        return e;
    }

    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public <T> T reattach(T object) {
        return manager.merge(object);
    }
}

すべてを1つのトランザクション内で実行する必要があります。

Context context = new InitialContext(your properties);
UserTransaction trans = (UserTransaction)context.lookup("java:comp/UserTransaction");
//AccessBean ab already injected;
//TheEntity e already exists

trans.begin(); //this implicates a new persistent context
e = da.reattach(e); //critical line
e.setText("New text");
e = da.updateEvent(e);
trans.commit();
TestCase.assertEquals("New text", e.getField()); //yes!

重要な線は一見不必要な線ですが、そうではありません。この行をコメントアウトすると、別の永続コンテキストにデタッチまたはアタッチされたエンティティを操作できます。次に、私の質問の問題であった面白い動作が表示されます。

注:これまでの明示的なトランザクション内のデータも取得する必要があります。

trans.begin();
e = da.reattach(e);
String s = e.getField();
trans.commit();
于 2011-11-10T12:10:02.787 に答える