[SEAM] 热帖:seam里面另人无奈的bug

darwinwen 2009-05-11
XML中的<begin-conversation join="true" flush-mode="manual"/>
等同于
@Begin(join = true,flushMode = FlushModeType.MANUAL)

意义是一样的,都是开启一个长会话,将flushMode设置为MANUAL,

将flushMode设置为MANUAL的原因,下面假如你是继承EntityHome或是HibernateEntityHome类,我以EntityHome源代码update方法为例说明.

/**
* Base class for Home objects of JPA entities.
*
* @author Gavin King
*
*/
public class EntityHome<E> extends Home<EntityManager, E> {


   @Transactional
   public String update()
   {
      joinTransaction();
      getEntityManager().flush();
      updatedMessage();
      raiseAfterTransactionSuccessEvent();
      return "updated";
   }

}

注意@Transactional事务标记以及getEntityManager().flush(),如果标记为@Begin(join = true),将flushMode将默认为AUTO,意味着你对在会话期间对实体做的任何修改,持入化上下文将直接进行脏检测,发现实体修改Seam容器将会自动调用getEntityManager().flush()方法清空缓存,提交到数据库,所以才会产生你现在的问题.将flushMode设置为MANUAL将是告诉Seam由你自己来调用getEntityManager().flush()方法,也就是你想要的做完验证之后合法的数据再提交到数据库.当然这些问题还有可能取决于你Entity的equals()和hashCode()方法的重写,这是Hibernate与JPA的知识,这里不作过多的讨论.



而改成这样之后 就不会出现以上的问题了,可是页面中的值却跟着改变了,我刷新也没用,直到我关闭页面 重新运行页面,它的值才会显示成最初未改动的值。。。而在整个过程当中,DB的数据是一直没变的(这是我想要的),可是我怎么样才能让页面的值不会出现那种“假象”??

这个问题,相信你已经理解Spring与Seam最大的区别,一个是无状态的,一个是有状态的,以及Seam的双向注入@In @Out, 当你注释@Beject标志,或是在XML写入一个begin-conversation节点,都代表是开启一个长会话,直到你标记@End或是在XML 写入<env-conversation>标记,才会结束当前这个会话,在会话期间你对@Name("")标记的实体进行的修改,Seam都会返回到Seam管理的上下文中,说白点就是把修改的后的对象重新复制一份到Seam上下文容器中,Seam容器透明的管理.

解决办法,下面的给你个例子参考.你可以使用在你的实体中使用增加一个@PostLoad标记方法,来将name的初始值保存到nameInitial临时变量中.

@Transient
private String nameInitial;

@NotNull
@Column(name = "ROLE_NAME", length = 50)
@Length(max = 50)
private String name;


@PostLoad
public void afterLoad() {
   this.nameInitial = this.name;
}
使用@PostLoad方法,这个是代表在实体装入时把name的初始值传给nameInitial,
这样你就可以保存你修改后name的初始值.

以上仅供参考,个人的理解.





无双Rama 2009-05-12
to darwinwen :
   解决办法,下面的给你个例子参考.你可以使用在你的实体中使用增加一个@PostLoad标记方法,来将name的初始值保存到nameInitial临时变量中.

@Transient
private String nameInitial;

@NotNull
@Column(name = "ROLE_NAME", length = 50)
@Length(max = 50)
private String name;


@PostLoad
public void afterLoad() {
   this.nameInitial = this.name;
}
使用@PostLoad方法,这个是代表在实体装入时把name的初始值传给nameInitial,
这样你就可以保存你修改后name的初始值.

这个方法可以,但是如果我的页面要修改的属性有很多个时,实体就写得很繁琐了。呵呵~~~~
非常感谢你的回复!! 
Global site tag (gtag.js) - Google Analytics