0

我在一个单元测试中使用嵌入式 OpenEJB。测试不起作用。当我调试时,我发现惰性获取的字段表现得很特别。

真的有可能吗?如果该字段已经加载,一切都照常进行:

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

但如果该字段尚未加载:

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

在我看到的调用堆栈中,顶部有一些覆盖层的方法,很可能是管理一个实体。我试过谷歌,但没有找到答案。

所以我的问题是:是否有一些规则,不能分配托管实体的未获取字段?如果有类似的规则,如何在不从数据库中获取字段的情况下更改字段的值?

4

1 回答 1

0

答案当然是肯定的。但是昨天发生了什么?

问题出在持久性上下文中,也可能出在方法名称中。该字段未在其设置器中更新。持久性上下文与事务绑定。因此,如果您需要更新和保存多个字段,则必须在一个事务中完成所有操作。您必须启动事务、调用实体上的设置器并调用会话 bean 上的更新方法来管理对实体的访问。

@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
}

在事务中可以调用或不调用 getter。但是必须在现有事务中调用 setter。相同的事务属性适用于会话 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);
    }
}

所有这些都必须在一笔交易中完成。

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 回答