我在一个单元测试中使用嵌入式OpenEJB。测试不起作用。当我调试时,我发现,懒惰的取出字段表现得特别。
真的有可能吗?如果该字段已经加载,则一切都以通常的方式进行:
//field == "something from db"
field = "ahoj";
//field == "ahoj"
但是如果该字段尚未加载:
//field == null
field = "ahoj";
//field == null
在我看到的调用堆栈中,顶部有一些覆盖层的方法,很可能是实体管理层。我试过谷歌,但没有找到答案。
所以我的问题是:是否有一些规则,不能分配被管实体的获取字段?如果有类似的规则,如何在不从数据库中获取字段的情况下更改字段的值?
答案 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();