2

我有这个问题:

我准备与实体的视图

@RequestMapping("/admin/modifyImplant/{id}")
 public ModelAndView modifyImplant(@PathVariable Integer id) {
  ModelAndView mav = new ModelAndView();

  Implant currentImplant =impDAO.findById(id); //this is the dao
  Implanttype it= currentImplant.getImplanttype();
  Implantinverter ii=new Implantinverter();
  ArrayList<Implantpanel> implantpanels = new ArrayList<Implantpanel>();
  try{
      ii= (Implantinverter)currentImplant.getImplantinverters().toArray()[0];
      implantpanels=(ArrayList<Implantpanel>) imppanelDAO.findByProperty("implant",currentImplant );
  }
  catch (Exception ex){
      //TODO
  }
  mav.addObject("implantpanels", implantpanels);
  mav.addObject("implantinverter",ii);
  mav.addObject("implant", currentImplant); //THIS IS THE ENTITY I MEAN
  mav.addObject("implanttype",it);
  mav.setViewName("/implant/modifyImplant.jsp");

  return mav;


}

这个jsp的代码方法(一小部分代码)

<form:form action="${pageContext.request.contextPath}/admin/finalizeModifyImplant/${implant.id}" method="POST" modelAttribute="implant">
        <table cellpadding="0" cellspacing="0" id="viewTable" >
            <tbody>
                <tr>
                <td class="label">
                    Name:
                </td>   
                <td>    
                    <form:input  id="User_namesurname" path="businessname" cssStyle="width:300px;"/>
                </td>
                </tr>

实体字段以此类推。实体有一些实体相关,通过外键连接(如implanttype、implantinverter、implantpanels)。

提交到这个控制器:

 @RequestMapping(value = "/admin/finalizeModifyImplant/{id}",
method = { RequestMethod.GET,RequestMethod.POST })
public ModelAndView finalizeModifyImplant(@PathVariable int id, @Valid @ModelAttribute Implant implant, BindingResult result){
    ModelAndView mav=new ModelAndView();
    mav.setViewName("../../admin/modifyImplant/"+id);
    if (result.hasErrors()){
        return mav;
    }

    implant.setId(id); //NOTICE WHAT I NEED TO DO HERE!
    Implant oldImplant= impDAO.findById(id);
    implant.setImplantinverters(oldImplant.getImplantinverters());
    implant.setImplantpanels(oldImplant.getImplantpanels());
    implant.setImplanttype(oldImplant.getImplanttype());
    implant.setInverters(oldImplant.getInverters());
    implant.setPvgis(oldImplant.getPvgis());
    try{
        impDAO.merge(implant); //here i call getSession().merge()
    }catch(RuntimeException re){
        return mav;
        //TODO: errors
    }

当我收到表单提交(这是一个更新)时,我有以下问题: 1. 返回的植入程序没有 id(字段 id=null) 2. 相关实体也为空。

以下是植入实体

public class Implant implements java.io.Serializable {
// Fields
private Integer id;
private Pvgis pvgis;
private Gateway gateway;
private Implanttype implanttype;
@JsonIgnore //I NEED TO JSONIGNORE IT BECAUSE IT HAS A RECURSIVE CALL ON IMPLANT
private Users users;
@NotEmpty
private String nameimplant;
private String place;
private double latitude;
private double longitude;
private double expectedpower;
private double tolerance;
[...] and many other fields

以及相关的implant.hbm.xml

<hibernate-mapping>
<class name="it.pstmarche.model.Implant" table="implant" schema="public">
    <id name="id" type="integer">
        <column name="id" />
        <generator class="identity" />
    </id>
    <many-to-one name="pvgis" class="it.pstmarche.model.Pvgis" fetch="select">
        <column name="idpvgis" />
    </many-to-one>
    <many-to-one name="gateway" class="it.pstmarche.model.Gateway" fetch="select">
        <column name="idgateway" />
    </many-to-one>
    <many-to-one name="implanttype" class="it.pstmarche.model.Implanttype" fetch="select">
        <column name="implanttype" />
    </many-to-one>
    <many-to-one name="users" class="it.pstmarche.model.Users" fetch="select" >
        <column name="iduser" />
    </many-to-one>
    <property name="nameimplant" type="string">
        <column name="nameimplant" not-null="true">
            <comment>Name</comment>
        </column>

我真的不知道如何正确进行更新,因为当我尝试从数据库(通过 findById 或直接查询)获取更新的实体时,我得到随机结果,有时我得到正确和更新的实体,有时我得到旧的实体!!真的很随意。

我试过:1.删除缓存( session.setCacheMode(CacheMode.IGNORE); )没有结果 2.添加 getSession().flush(); getSession().close(); 在合并方法的最后,即:

public void merge(Implant currentImp){
    //Session session = HibernateSessionFactory.getSessionFactory().openSession();
    Transaction tx= getSession().beginTransaction();
    if (currentImp.getId() != null) { // it is an update
        getSession().merge(currentImp);
        tx.commit();
        //getSession().update(currentImp);
        log.debug("MERGE");
        getSession().flush();// THAT'S THE ADD
        session.close(); //THIS IS ALSO
    } else { // you are saving a new one
        getSession().saveOrUpdate(currentImp);
        tx.commit();
        getSession().flush();
        getSession().close();
        log.debug("Save sou");
    }

我真的不知道用 Hibernate + Spring 实现更新的正确方法是什么!任何帮助表示赞赏。谢谢

编辑:也许我的问题不清楚。当前的问题是,在我随机保存或合并实体后,当我搜索实体(例如通过查询 findById(int id))时,我随机得到旧实体(我认为它仍在休眠会话中)。解决此问题的唯一方法是清除会话(getSession().clear()),但在此之后我显然得到了延迟异常 -当我尝试获取我需要的实体的相关实体时,没有代理在清除中会议!真可惜

2EDIT:感谢 Tim H。但是,我仍然面临与处理休眠会话相关的问题。前言:我使用每个线程的休眠会话,比如

private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private  static Configuration configuration = new Configuration();    
private static org.hibernate.SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
static {
    try {
        configuration.configure(configFile);
        sessionFactory = configuration.buildSessionFactory();
    } catch (Exception e) {
        System.err
                .println("%%%% Error Creating SessionFactory %%%%");
        e.printStackTrace();
    }
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
    Session session = (Session) threadLocal.get();
    if (session == null || !session.isOpen()) {
        if (sessionFactory == null) {
            rebuildSessionFactory();    
        }
        session = (sessionFactory != null) ? sessionFactory.openSession()
                : null;
        threadLocal.set(session);
    }
    return session;
}

现在,假设我在 Tomcat 线程 1 上从数据库加载实体 x。实体值为100。加载后我无法关闭会话,因为它是延迟初始化的(如果我关闭会话,我可能会遇到延迟初始化异常 - 无代理/会话)。

之后,我更新线程 2 上实体 x 的值。现在的值为50

最后,我加载了值,但是 tomcat 让我进入线程 1,实体仍在线程的会话中,值仍然是 100。我得到的是旧值而不是新值!!

所以,在我的 jsp 完成之前我无法关闭会话(我使用惰性字段),我必须通过以下方式在 jsp 结束时关闭会话:<% HibernateSessionFactory.getSession().close (); %> 这太可怕了!我将视图与模型结合起来!有一种模式可以安全地做到这一点?

4

2 回答 2

1

我也许可以阐明您的一些问题。

  1. 如果请求参数与您的实体上的 id 属性匹配(即隐藏的表单字段),您的 id 只会绑定到您的实体。

  2. 对于绑定的其余部分,您可能想要使用所谓的“@ModelAttribute”技巧。基本上,任何使用 @ModelAttribute 注释的方法都将在所有请求之前被调用,因此此方法将返回 Spring 将形成的实体,然后从您的表单中绑定您的支持对象,就像这样。

    @ModelAttribute Implant 植入 public Implant getBackingImplant(HttpServletRequest request) { if(request.getParameter("id") != null return dao.getImplantByIdWithAllMyRelationshipsFilledIn(request.getParameter("id");

    返回新的植入物();}

因此,现在 spring 会将您的表单与 getBackingImplant 返回的实体绑定。

至于你的保存不起作用,我真的不确定我不是一个冬眠的人,但上面应该解决你的表单绑定问题。

于 2012-04-19T00:53:28.220 回答
0

添加一个新答案,因为现在问题更清楚了。请记住,合并返回它合并的实体,您正在丢弃合并命令的结果,而是应该将其返回给您的控制器。

于 2012-04-19T11:45:31.277 回答