可以在加载之前修改lazy fetched字段吗?

时间:2011-11-08 20:28:19

标签: jpa java-ee-6 openjpa openejb

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

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

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

但是如果该字段尚未加载:

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

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

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

1 个答案:

答案 0 :(得分:0)

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

问题出在持久化上下文中,也可能在方法名称中。该字段未在其setter中更新。持久化上下文与事务绑定。因此,如果您需要更新并保存多个字段,则必须在一个事务中执行所有操作。您必须启动事务,在实体上调用setter并在会话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
}

可以在事务中调用或不调用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();