SSH版本:
struts 2.2.1
hibernate 3
spring 3.0.4同一个项目里面有一个用户的增删改查流程,有一个产品类型的增删改查流程。用户的那个没有问题,产品类型的出了这样一个问题:
先新增一个,然后删除,再新增的时候在页面报错500,错误信息如下:
org.springframework.orm.hibernate3.HibernateSystemException: could not reassociate uninitialized transient collection; nested exception is org.hibernate.HibernateException: could not reassociate uninitialized transient collection
查了网上的资料,在spring的配置文件中增加了scope="prototype",如下:<bean id="furnituretypeAction" class="com.redwood.action.FurnituretypeAction" scope="prototype">
<property name="furnituretypeBiz" ref="furnituretypeBiz"></property>
</bean>然后问题解决了,但是新的问题就又出来了。对产品类型中的一个进行修改时,发现页面又报另外的错误了:
org.springframework.dao.InvalidDataAccessApiUsageException: The given object has a null identifier: com.redwood.entity.Furnituretype; nested exception is org.hibernate.TransientObjectException: The given object has a null identifier: com.redwood.entity.Furnituretype
在spring的xml里面我分别加scope="prototype",和不加scope="prototype",用断点调试发现:
不加scope="prototype",报错是因为新增时,主键居然不为null;
相反,增加scope="prototype"后,进入update方法后,主键居然为null。
最后的解决方法:我在修改的那个页面增加了一个隐藏表单域,把主键取出来,有用表单提交给action后问题彻底解决!
我的问题是:
1.我最后的这种处理方式是否合理?
2.为什么会出现这种问题?
3.为什么用户管理的那个增删改查流程就没出问题?
4.求解释,谢谢!

解决方案 »

  1.   

    我的问题是:
    1.我最后的这种处理方式是否合理?
    也算合理,只是有点奇怪update时为什么你的主key是null,你的页面信息和你的action是怎么关联的?一般如果你的页面使用的是action的某个entity,那么提交的时候,这个entity的信息是都能自动取到的,想象不到你的key是怎么丢失的,这个要看你的jsp是怎么写的。
    2.为什么会出现这种问题?
    如果没有scope="prototype",default就是sinleton,也就是单实例,那么所有的处理用的是同一个action,那么action里面的entity信息可能会冲突3.为什么用户管理的那个增删改查流程就没出问题?
    这个要查看你的jsp和action的代码才能知道4.求解释,谢谢!
      

  2.   

    加了scope="prototype“之后,保证action不是单例的,每提交一次请求,都创建一个action实例。开始楼主没有加,新增时主键不空,因为action是单例的,再次新增得到的主键是刚才删掉的那条记录的主键。在form上写一个隐藏域,来放置主键,这种方式也可以。
      

  3.   

    JSP代码如下:<%@ page language="java" pageEncoding="utf-8"%>
    <%@ taglib uri="/struts-tags" prefix="s" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>更新产品类型</title>
    </head><body>
    <center>
        <form action="furnituretype!updType" method="post" name="updateform">
        <input type="hidden" name="furnituretype.typeId" id="furnituretype.typeId" value="<s:property value="furnituretype.typeId"/>"/>
           <table>
              <tr>
                 <td>产品类型:</td>
                 <td><input type="text" name="furnituretype.type" id="furnituretype.type" value="<s:property value="furnituretype.type"/>"/></td>
              </tr>
              <tr>
                 <td colspan="2">
                   <input type="submit" name="sub" value=" 提 交 "/>
                 </td>
              </tr>
           </table>
        </form>
    </center>
    </body>
    </html>
    action代码如下:package com.redwood.action;import java.util.List;import com.redwood.biz.IFurnituretypeBiz;
    import com.redwood.entity.Furnituretype;public class FurnituretypeAction extends BaseAction<Furnituretype> { private int id;
    private Furnituretype furnituretype;
    private List<Furnituretype> listfurnituretype;
    private IFurnituretypeBiz furnituretypeBiz;

    public int getId() {
    return id;
    }
    public void setId(int id) {
    this.id = id;
    }
    public Furnituretype getFurnituretype() {
    return furnituretype;
    }
    public void setFurnituretype(Furnituretype furnituretype) {
    this.furnituretype = furnituretype;
    }
    public List<Furnituretype> getListfurnituretype() {
    return listfurnituretype;
    }
    public void setListfurnituretype(List<Furnituretype> listfurnituretype) {
    this.listfurnituretype = listfurnituretype;
    }
    public IFurnituretypeBiz getFurnituretypeBiz() {
    return furnituretypeBiz;
    }
    public void setFurnituretypeBiz(IFurnituretypeBiz furnituretypeBiz) {
    this.furnituretypeBiz = furnituretypeBiz;
    }


    /**
     * 根据ID得到一个实体
     * @return
     */
    public String getById(){
    furnituretype=furnituretypeBiz.getById(id);
    return "update";
    }

    /**
     * 获得所有的实体
     * @return
     */
    public String getAll(){
    listfurnituretype=furnituretypeBiz.getAll();
    return "showtype";
    }

    /**
     * 新增
     * @return
     */
    public String addType(){
    furnituretypeBiz.save(furnituretype);
    getAll();
    return "showtype";
    }

    /**
     * 删除
     * @return
     */
    public String delType(){
    furnituretype=furnituretypeBiz.getById(id);
    furnituretypeBiz.delete(furnituretype);
    getAll();
    return "showtype";
    }

    /**
     * 修改
     * @return
     */
    public String updType(){
    furnituretypeBiz.update(furnituretype);
    getAll();
    return "showtype";
    }

    }
      

  4.   

    从你的现象来看,是上一个action转到jsp,然后提交到下一个action时,valuestack 内容没有传递,查了一下,好像只有chain result方式chain拦截器会复制valuestack,默认的dispatcher方式是params拦截器把参数设置到valuestack里,所以页面有传递的参数action才能取到,也就是上一个action的valuestack信息丢失,即id信息丢失,所以你用隐藏域的时候,隐藏域取出了上一个action的valuestack的id信息,提交时当做参数传递到了下一个action的valuestack里,所以就不出错了。这个只能有时间再去看看研究一下整个请求过程的源码了。默认的dispatcher方式是传递request/response的,LZ可以把id或整个对象信息保存到request或session里(attribute),然后在action里取出来也可以。
      

  5.   

    感谢大家的回帖!我也发现:当对没有主外键关联的表进行操作(增删改查)时没有问题,不加scope="prototype",都没问题;只有对有主外键关系的表进行操作时才会出现。补充下,我的整个框架用的泛型结构!