惰性 LOB 更改时实体数据重置
Entity data reset when a lazy LOB is changed
我正在使用 Glassfish 4 (JavaEE7) 和 EclipseLink (JPA2.1) 进行一个大项目。
当我修改 LOB 字段的值时,这会重置所有先前的实体值。
例如,我有以下实体:
@Entity
@Table(name="person")
public class Person implements Serializable {
@Id
@Column(name = "ID")
private Integer id;
@Column(name = "LASTNAME")
private String lastname;
@Column(name = "FIRSTNAME")
private String firstname;
@Column(name = "VERSION")
private Integer version;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "REMARKS")
private String remarks;
/* getter & setters */
}
我使用以下代码更新我的实体:
@Singleton
@TransactionManagement(TransactionManagementType.BEAN)
@Startup
public class ModifierBean implements ModifierBeanLocal {
@Resource
private UserTransaction userTransaction;
@PersistenceContext
private EntityManager entityManager;
@Override
public String modify(Integer id, String lastname, String firstname, String remarks) {
try {
StringBuilder result = new StringBuilder(256);
userTransaction.begin();
Query query = entityManager.createQuery("SELECT p FROM Person p WHERE p.id = ?1");
query.setParameter(1, id);
Person p = (Person)query.getSingleResult();
result.append("State 0: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
p.setFirstname(firstname);
p.setLastname(lastname);
p.setVersion(p.getVersion()+1);
result.append("State 1: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
p.setRemarks(remarks); // <= reset the other fields
result.append("State 2: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
userTransaction.commit();
return result.toString();
} catch(Exception e) {
//...
}
}
}
当我运行下面的代码时,这里是我从 Bean 得到的输出:
State 0: lastname=Smith, firstname=John, version=0
State 1: lastname=John2, firstname=Smith2, version=1
State 2: lastname=Smith, firstname=John, version=0
正如你所看到的,当加载 LOB 时,then 实体的值被重置,这对我来说非常烦人。
有一些技巧可以防止这种情况发生,例如我测试了以下选项:
- 在修改 LOB 字段之前调用 entityManager.flush()
- 在进行第一次修改之前调用 p.getRemarks() juste
我还注意到,如果 LOB 字段未更改,则值已正确提交。
我知道 LAZY 值是按需加载的,但我不明白为什么它会重置所有其他值。
这是错误还是标准行为?有什么方法可以让它按预期工作(不重置值)?
这取决于您的持久性单元属性及其与事务的关联。不过我相信,由于您没有明确地将 EntityManager 加入事务,Em 的行为就好像它在事务之外导致应用以下行为:
"Outside transaction entire object (fetch group members included) is refreshed in the shared cache."
http://wiki.eclipse.org/EclipseLink/Development/2.1/AdvancedJPA_Queries/FetchGroup
尝试调用 entityManager.joinTransaction();开始交易后看看这是否有帮助。 EclipseLink
我刚刚发现这个确切的错误已在 EclipseLink 中打开(自 v2.1.3 以来已经存在):https://bugs.eclipse.org/bugs/show_bug.cgi?id=371743
我正在使用 Glassfish 4 (JavaEE7) 和 EclipseLink (JPA2.1) 进行一个大项目。 当我修改 LOB 字段的值时,这会重置所有先前的实体值。
例如,我有以下实体:
@Entity
@Table(name="person")
public class Person implements Serializable {
@Id
@Column(name = "ID")
private Integer id;
@Column(name = "LASTNAME")
private String lastname;
@Column(name = "FIRSTNAME")
private String firstname;
@Column(name = "VERSION")
private Integer version;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "REMARKS")
private String remarks;
/* getter & setters */
}
我使用以下代码更新我的实体:
@Singleton
@TransactionManagement(TransactionManagementType.BEAN)
@Startup
public class ModifierBean implements ModifierBeanLocal {
@Resource
private UserTransaction userTransaction;
@PersistenceContext
private EntityManager entityManager;
@Override
public String modify(Integer id, String lastname, String firstname, String remarks) {
try {
StringBuilder result = new StringBuilder(256);
userTransaction.begin();
Query query = entityManager.createQuery("SELECT p FROM Person p WHERE p.id = ?1");
query.setParameter(1, id);
Person p = (Person)query.getSingleResult();
result.append("State 0: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
p.setFirstname(firstname);
p.setLastname(lastname);
p.setVersion(p.getVersion()+1);
result.append("State 1: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
p.setRemarks(remarks); // <= reset the other fields
result.append("State 2: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
userTransaction.commit();
return result.toString();
} catch(Exception e) {
//...
}
}
}
当我运行下面的代码时,这里是我从 Bean 得到的输出:
State 0: lastname=Smith, firstname=John, version=0
State 1: lastname=John2, firstname=Smith2, version=1
State 2: lastname=Smith, firstname=John, version=0
正如你所看到的,当加载 LOB 时,then 实体的值被重置,这对我来说非常烦人。 有一些技巧可以防止这种情况发生,例如我测试了以下选项:
- 在修改 LOB 字段之前调用 entityManager.flush()
- 在进行第一次修改之前调用 p.getRemarks() juste
我还注意到,如果 LOB 字段未更改,则值已正确提交。 我知道 LAZY 值是按需加载的,但我不明白为什么它会重置所有其他值。
这是错误还是标准行为?有什么方法可以让它按预期工作(不重置值)?
这取决于您的持久性单元属性及其与事务的关联。不过我相信,由于您没有明确地将 EntityManager 加入事务,Em 的行为就好像它在事务之外导致应用以下行为:
"Outside transaction entire object (fetch group members included) is refreshed in the shared cache." http://wiki.eclipse.org/EclipseLink/Development/2.1/AdvancedJPA_Queries/FetchGroup
尝试调用 entityManager.joinTransaction();开始交易后看看这是否有帮助。 EclipseLink
我刚刚发现这个确切的错误已在 EclipseLink 中打开(自 v2.1.3 以来已经存在):https://bugs.eclipse.org/bugs/show_bug.cgi?id=371743