`
songxh2
  • 浏览: 132359 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

求助Hibernate的单向Many-to-one关系问题。

阅读更多

一、问题特征如下:
      我在使用单向Many-to-one关系时,主要是想用作数据字典链接,1的一端是基本不变的数据,所以希望仅在many的这边进行引用。引用的方式有:
1.创建的时候新建引用;
2.修改的时候可以更新引用;

我是用saveupdate(instance)来保存数据的,但是发现刚创建的时候保存对象没有问题,保存后马上接着修改也没有问题。
但是,我发现如果指定一个修改对象进行修改,则出错。


错误如下:
org.hibernate.HibernateException: identifier of an instance of test.Parent was altered from 2 to 1

使用merge,saveupdate,save,update等方法,都出现几乎同样的错误。让我头都大了,网上查资料,说这类的错误出现的几率少,没搜到更详细的错误报告。我一一排查,把关联映射、生产环境等去掉重来,排查到最后才发现,新建并修改不出问题,但是事后指定一个对象修改,却发生上面的错误。估计耗时两三天了吧,我估计是对象状态的问题,但又不知何从下手。。我能力有限,希望各位给些意见。

二、下面给出我的一下代码和测试报告:

1.保存对象含单向多对一关系。

被测试对象test.Child的hbm:

<hibernate-mapping>
    <class name="test.Child" table="app_child" schema="dbo">

       <id name="id" column="ChildId" type="integer">
           <generator class="identity">generator>
       id>

       <property name="name" type="string">
           <column name="name" length="50" not-null="true">column>
       property>
       <many-to-one name="parent" class="test.Parent" column="ParentID"
           outer-join="true">
       many-to-one>
    </class>
</hibernate-mapping>
 

2.被关联对象test.Parent如下hbm:
<hibernate-mapping>
<class name="test.Parent" table="app_parent" schema="dbo">
    <id name="id" column="ParentId" type="integer"><generator class="identity">generator>id>
    <property name="name" type="string">
        <column name="name" length="50" not-null="true" unique="true">column>
    property>
</class>
</hibernate-mapping>


3.操作页面jsf。Backingbean如下:

package test;

import net.xerllent.system.web.BasePage;
import org.springframework.dao.DataAccessException;
import java.util.Map;
public class TestForm extends BasePage {

 private Child child;
 private ChildDAO childDAO;
 
 public Child getChild() {
 
  if(child==null){
//   child=(Child)childDAO.getChild(new Integer(3));
   child=(Child)childDAO.loadChild(new Integer(3));
   if(child==null) {
    child=new Child();
   }
  }
  return child;
 }

 public void setChild(Child child) {
  this.child = child;
 }

 public void setChildDAO(ChildDAO childDAO) {
  this.childDAO = childDAO;
 }
 
 
 public String merge() {
  try {
   childDAO.merge(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public String persist() {
  try {
   childDAO.persist(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public String refresh() {
  try {
   childDAO.refresh(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public String replicate() {
  try {
   childDAO.replicate(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public String save() {
  try {
   childDAO.save(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public String saveOrUpdate() {
  try {
   childDAO.saveOrUpdate(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public String update() {
  try {
   childDAO.update(child);
   return "success";
  } catch (RuntimeException e) {
   return "success";
  }
 }

 public Map getDictParents(){
  return childDAO.getParentsMapList();
 }
 public Map getDictParentbs(){
  return childDAO.getParentbsMapList();
 }
}

4.Spring2-Hibernate3的merge,persist,refresh,replicate,save,saveOrUpdate,update方法测试表

方法测试方案 merge persist refresh Replicate
(Replica
tionMode.
OVERWRITE)
save saveOrUpdate update
新建对象第一次保存,选择了parentId
『提示:
many-to-one属性update=true』
保存成功!普通字段及关联字段都保存成功。 没有反应 不保存数据,页面数据恢复成原来数据库里的值,sql日志中没有update语句 页面显示数据与数据库不一致。Sql日志中没有update操作语句。 Save总是插入新的记录,不能做修改操作 可以修改普通字段及关联字段。 可以修改普通字段及关联字段。
新建对象保存后马上接着修改操作 保存成功!普通字段及关联字段都保存成功。 没有反应 不保存数据,页面数据恢复成原来数据库里的值,sql日志中没有update语句 页面显示数据与数据库不一致。Sql日志中没有update操作语句。 Save总是插入新的记录,不能做修改操作 可以修改普通字段及关联字段。 可以修改普通字段及关联字段。
从数据库搜索出来修改普通字段时 保存成功!数据库与页面显示一致,日志sql中有update语句 没错误提示,保存不成功,数据库是原来的值,但页面的值是新修改的,不一致,sql中没有update语句 不保存数据,页面数据恢复成原来数据库里的值,sql日志中没有update语句。 不保存修改数据,页面显示数据与数据库不一致。Sql日志中没有update操作语句。 修改数据成功!数据库数据与页面一致。Sql日志中有update操作语句 修改数据成功!数据库数据与页面一致。Sql日志中有update操作语句。 修改数据成功!数据库数据与页面一致。Sql日志中有update操作语句。
从数据库搜
索出来修改关联字段值parentId时(注意child.
parent.
parentId
的值改了,
其他值null。是个比较脏的数据。
Merge不起作用,数据库的值没有改变,与页面显示数据不一直,如果刷新页面,页面的值将恢复到数据库值。
错误提示:
org.
hibernate.
Hibernate
Exception:
identifier
of an
instance
of test.
Parent
was altered
from 2 to 1
没错误提示,保存不成功,数据库是原来的值,但页面的值是新修改的,不一致,sql中没有update语句。Persistent表示将被操作对象用持久化对象替代。不返回持久化对象 不保存数据,页面数据恢复成原来数据库里的值,sql日志中没有update语句。被修改对象将被持久化对象取代,并返回持久化对象 不保存修改数据,页面显示数据与数据库不一致。Sql日志中没有update操作语句。 修改错误,系统提示:
Hibernate
Transaction
Manager.
doRollback
OnCommit
Exception
(801) |
Initiating
transaction
rollback
after commit
exceptionorg
.spring
framework
.orm.
hibernate
3.Hibernate
System
Exception:
identifier
of an
instance
of test.
Parent
was altered
from 2 to 1;
修改错误,系统提示:
Hibernate
Transaction
Manager.
doRollback
OnCommit
Exception
(801) |
Initiating
transaction
rollback
after commit
exceptionorg
.spring
framework
.orm.
hibernate
3.Hibernate
System
Exception:
identifier
of an
instance
of test.
Parent
was altered
from 2 to 1;
修改错误,系统提示:
Hibernate
Transaction
Manager.
doRollback
OnCommit
Exception
(801) |
Initiating
transaction
rollback
after commit
exceptionorg
.spring
framework
.orm.
hibernate
3.Hibernate
System
Exception:
identifier
of an
instance
of test.
Parent
was altered
from 2 to 1;

分享到:
评论
15 楼 wenbin151 2007-09-30  
强,谢谢!前人栽树,后人乘凉!!!!!站在您的肩膀上,我们轻松完成了任务!
14 楼 songxh2 2007-08-16  
问题基本解决,问题在于jsf的backingbean对象更新机制。。。需要用如下方法避免。

 /* 用户提交页面时,backing bean 的getChild()方法应该提供一个临时对象让jsf来组装更新数据比较合适,
 * 因为jsf恢复数据时首先会用这个方法取个原始对象,然后在这个对象的基础上组装新的数据。
 * 注意一定先提供一个临时对象而非持久化对象,因为在组装数据时,会用新数据替换旧数据,
 * 如果被替换的是持久化对象及其子对象的Id值时(比如child.parent.id),其实你可能只是是想替换与parent的关系,
 * 但jsf系统并不知道你是想要建立新的关系,所以会抛出子对象的Id被强制修改的错误!而持久化对象的Id值是不能被更改的。

 * backing bean 的getChild()方法必须在用户提交页面时应该提供一个临时对象,jsf恢复数据会用这个方法取原始对象,注意一定先提供一个临时对象而非持久化对象,
 * 因为在组装数据时,会用新数据替换旧数据,如果被替换的是持久化对象,在替换子对象关系时,会检查到子对象的Id被强制修改的错误!
 */
public Child getChild() {
	if(child==null){
		//child=(Child)childDAO.getChild(new Integer(4));不能直接实例化session对像,不然jsf会强制更新这个持久化对象的任何值,碰到many-to-one的关系更新,它也会认为是修改原来的持久化对象(应该是替换不是修改),而在修改id值时会抛出错误,无法保存数据。
		child=new Child();  //临时对象
	}
return child;
}
13 楼 songxh2 2007-08-15  
引用
好像你的parent对象一直在session的管理之下,是一个持久化对象,而并非如你所说的 “只对parent的id属性设置了值,其他值都为空”的一个临时对象,这样虽然没有对parent对象做更新操作,但是当事务提交时,hibernate会自动把对持久化对象的修改保存到数据库中,检查发现id发生了改变,所以报错。

你的对象为什么一直在session的管理之下呢,是每次request到来时提前准备好的还是每次session都不关?


我用了 在web.xml中用了Spring 的 opensessionviewFilter过滤器的,在web应用的时候是打开的。

	<filter>
		<filter-name>OpenSessionInViewFilter</filter-name>
		<filter-class>
			org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
		</filter-class>
		<init-param>
			<param-name>singleSession</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
12 楼 janh 2007-08-15  
好像你的parent对象一直在session的管理之下,是一个持久化对象,而并非如你所说的 “只对parent的id属性设置了值,其他值都为空”的一个临时对象,这样虽然没有对parent对象做更新操作,但是当事务提交时,hibernate会自动把对持久化对象的修改保存到数据库中,检查发现id发生了改变,所以报错。

你的对象为什么一直在session的管理之下呢,是每次request到来时提前准备好的还是每次session都不关?
11 楼 songxh2 2007-08-15  
songxh2 写道
janh 写道
修改对象应该在持久化对象的基础上进行修改。
根据id,get获取到对应的持久化对象,再设置要改变的属性值。
关联对象也同样,根据父id,get获取到anotherParent,再child.setParent(anotherParent);


谢谢!说的有理,建议加50分。


但是还是发现问题依然存在!!!!!

我如你所说添加了如下修改方式代码,(其实我原来也做过这个测试,只是不很确定..)

public String update() {
	try {
		//得到新的Id及其持久化对象p,并重新设置child的parent
		Integer pid=child.getParent().getId();
		Parent p=childDAO.getParentById(pid);
		child.setParent(p);

		childDAO.update(child);//此步依然出现错误!!!!
		return "success";
	} catch (RuntimeException e) {
		return "success";
	}
}



错误原因还是:
org.hibernate.HibernateException: identifier of an instance of test.Parent was altered from 1 to 2

不得其解,难道不是不能修改二级对象的id,而是其他原因?比如单向many-to-one关联不能更新关联关系?
10 楼 songxh2 2007-08-15  
janh 写道
修改对象应该在持久化对象的基础上进行修改。
根据id,get获取到对应的持久化对象,再设置要改变的属性值。
关联对象也同样,根据父id,get获取到anotherParent,再child.setParent(anotherParent);


谢谢!说的有理,建议加50分。
9 楼 janh 2007-08-15  
修改对象应该在持久化对象的基础上进行修改。
根据id,get获取到对应的持久化对象,再设置要改变的属性值。
关联对象也同样,根据父id,get获取到anotherParent,再child.setParent(anotherParent);
8 楼 songxh2 2007-08-15  
janh 写道
不能修改持久化对象的id值


我在getChild()里加了个attachClean方法,但错误依旧!!

	public Child getChild() {
		
		if(child==null){
			child=(Child)childDAO.getChild(new Integer(4));
//			child=(Child)childDAO.loadChild(new Integer(3));
			if(child==null) {
				child=new Child();
			}
			childDAO.attachClean(child);
			childDAO.attachClean(child.getParent());
			childDAO.attachClean(child.getParentb());
		}
		return child;
	}
7 楼 songxh2 2007-08-15  
janh 写道
不能修改持久化对象的id值

非常感谢!你这句话说到我心坎上去了,但我要修改这个对象的关联值,但如何实现呢?

我这样想,难道被修改的对象的子对象在jsf里都不能直接赋值,必须另在backingbean里先设置个该子对象的Id变量,接受到更改后的Id值后再实例化二级对象,然后再关联!!!这也太麻烦了吧。

或者我怎么先去掉持久化状态呢?,再修改之。就像我新建这个对象后马上接着修改并能正确保存的这个状态。

用这句话可以解决问题吗?

	/* (non-Javadoc)
	 * @see net.xerllent.system.dao.imp.BaseDao#attachClean(java.lang.Object)
	 */
	public void attachClean(Object instance) {
		log.debug("attaching clean Object instance");
		try {
			getHibernateTemplate().lock(instance, LockMode.NONE);
			log.debug("attach successful");
		} catch (RuntimeException re) {
			log.error("attach failed", re);
			throw re;
		}
	}
6 楼 janh 2007-08-15  
不能修改持久化对象的id值
5 楼 songxh2 2007-08-15  
较完整错误消息:

[donuts] DEBUG [http-8080-2] HibernateTransactionManager.handleExistingTransaction(444) | Participating in existing transaction
[donuts] DEBUG [http-8080-2] TransactionInterceptor.prepareTransactionInfo(282) | Getting transaction for [test.ChildDAO.update]
[donuts] DEBUG [http-8080-2] TransactionSynchronizationManager.getResource(140) | Retrieved value [org.springframework.orm.hibernate3.SessionHolder@204443] for key [org.hibernate.impl.SessionFactoryImpl@f61227] bound to thread [http-8080-2]
[donuts] DEBUG [http-8080-2] TransactionSynchronizationManager.getResource(140) | Retrieved value [org.springframework.orm.hibernate3.SessionHolder@204443] for key [org.hibernate.impl.SessionFactoryImpl@f61227] bound to thread [http-8080-2]
[donuts] DEBUG [http-8080-2] HibernateTemplate.execute(364) | Found thread-bound Session for HibernateTemplate
[donuts] DEBUG [http-8080-2] HibernateTemplate.execute(388) | Not closing pre-bound Hibernate Session after HibernateTemplate
[donuts] DEBUG [http-8080-2] TransactionInterceptor.commitTransactionAfterReturning(312) | Completing transaction for [test.ChildDAO.update]
[donuts] DEBUG [http-8080-2] TransactionInterceptor.commitTransactionAfterReturning(312) | Completing transaction for [test.ChildDAO.update]
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.triggerBeforeCommit(833) | Triggering beforeCommit synchronization
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.triggerBeforeCompletion(846) | Triggering beforeCompletion synchronization
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.processCommit(660) | Initiating transaction commit
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.doCommit(571) | Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@1077c9d]
[donuts] DEBUG [http-8080-2] JDBCTransaction.commit(103) | commit
[donuts] DEBUG [http-8080-2] AbstractFlushingEventListener.prepareEntityFlushes(111) | processing flush-time cascades
[donuts] DEBUG [http-8080-2] AbstractFlushingEventListener.prepareCollectionFlushes(154) | dirty checking collections
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.doRollbackOnCommitException(801) | Initiating transaction rollback after commit exception
org.springframework.orm.hibernate3.HibernateSystemException: identifier of an instance of test.Parent was altered from 1 to 2; nested exception is org.hibernate.HibernateException: identifier of an instance of test.Parent was altered from 1 to 2
Caused by: 
org.hibernate.HibernateException: identifier of an instance of test.Parent was altered from 1 to 2
	at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:58)
	at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:157)
	at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:113)
	at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
	at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
	at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:575)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
	at $Proxy10.update(Unknown Source)
	at test.TestForm.update(TestForm.java:89)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.el.parser.AstValue.invoke(AstValue.java:131)
	at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
	at org.apache.jasper.el.JspMethodExpression.invoke(JspMethodExpression.java:68)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:77)
	at org.apache.myfaces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:54)
	at javax.faces.component.UICommand.broadcast(UICommand.java:383)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:447)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:752)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:97)
	at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:75)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:147)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
	at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
	at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
	at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
	at java.lang.Thread.run(Unknown Source)
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.doRollback(590) | Rolling back Hibernate transaction on Session [org.hibernate.impl.SessionImpl@1077c9d]
[donuts] DEBUG [http-8080-2] JDBCTransaction.rollback(152) | rollback
[donuts] DEBUG [http-8080-2] JDBCTransaction.toggleAutoCommit(193) | re-enabling autocommit
[donuts] DEBUG [http-8080-2] JDBCTransaction.rollback(163) | rolled back JDBC Connection
[donuts] DEBUG [http-8080-2] ConnectionManager.afterTransaction(302) | transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.triggerAfterCompletion(875) | Triggering afterCompletion synchronization
[donuts] DEBUG [http-8080-2] TransactionSynchronizationManager.clearSynchronization(276) | Clearing transaction synchronization
[donuts] DEBUG [http-8080-2] TransactionSynchronizationManager.unbindResource(193) | Removed value [org.springframework.jdbc.datasource.ConnectionHolder@19747c9] for key [org.apache.commons.dbcp.BasicDataSource@190690e] from thread [http-8080-2]
[donuts] DEBUG [http-8080-2] HibernateTransactionManager.doCleanupAfterCompletion(657) | Not closing pre-bound Hibernate Session [org.hibernate.impl.SessionImpl@1077c9d] after transaction
[donuts] DEBUG [http-8080-2] SessionImpl.disconnect(374) | disconnecting session
[donuts] DEBUG [http-8080-2] ConnectionManager.closeConnection(441) | releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[donuts] DEBUG [http-8080-2] ConnectionManager.afterTransaction(302) | transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
[donuts] DEBUG [http-8080-2] DelegatingVariableResolver.resolveVariable(106) | Attempting to resolve variable 'TestForm' in via original VariableResolver
4 楼 songxh2 2007-08-15  
movingboy 写道
建议把如何设置Child实例的parent属性的代码也贴出来

我设置Child实例的parent属性时,根据jsf默认的<h:selectOneMenu>的特性,只对parent的id属性设置了值,其他值都为空。

但是为什么新建后马上接着修改没问题,而事后从数据库指定一个记录对象修改的时候却出错呢?
3 楼 songxh2 2007-08-15  
jsf页面代码如下:(提示我的spring OpenSessionInViewFilter是打开的)

<%@taglib uri="http://www.xerllent.cn/donuts" prefix="xer"%>
<%@ page language="java" pageEncoding="GB18030"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

//FacesContext ctx=FacesContext.getCurrentInstance();
//ChildDAO cdao=(ChildDAO)ctx.getApplication().getVariableResolver().resolveVariable(ctx,"ChildDAO");
//cdao.addRole();
//cdao.testdelete();

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
	<base href="<%=basePath%>">

	<title>My JSF 'testParentChild.jsp' starting page</title>
	
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

</head>
  
<body>
	<f:view>
		This is my JSF JSP page. <br>
		<h:form>
		<h:messages showSummary="true"></h:messages>
		<h:inputHidden value="#{TestForm.child.id}"></h:inputHidden>
		<h:panelGrid columns="3">

		<t:outputLabel for="name" value="名称"></t:outputLabel>
		<h:inputText id="name" value="#{TestForm.child.name}" required="true"></h:inputText>
		<h:message for="name"></h:message>

		<t:outputLabel for="parent" value="父系统:"></t:outputLabel>
		<t:selectOneMenu id="parent" value="#{TestForm.child.parent.id}" required="true">
			<f:selectItems value="#{TestForm.dictParents}"/>
		</t:selectOneMenu>
		<h:message for="parent"></h:message>
		<t:outputLabel for="parentb" value="父系统b:"></t:outputLabel>
		<t:selectOneMenu id="parentb" value="#{TestForm.child.parentb.code}" required="true">
			<f:selectItems value="#{TestForm.dictParentbs}"/>
		</t:selectOneMenu>
		<h:message for="parentb"></h:message>
		<h:commandButton  action="#{TestForm.merge}" value="merge" type="submit"/>	
		<h:commandButton  action="#{TestForm.persist}" value="persist" type="submit"/>	
		<h:commandButton  action="#{TestForm.refresh}" value="refresh" type="submit"/>	
		<h:commandButton  action="#{TestForm.replicate}" value="replicate" type="submit"/>	
		<h:commandButton  action="#{TestForm.save}" value="save" type="submit"/>	
		<h:commandButton  action="#{TestForm.saveOrUpdate}" value="saveOrUpdate" type="submit"/>	
		<h:commandButton  action="#{TestForm.update}" value="update" type="submit"/>	
		</h:panelGrid>
		</h:form>
	</f:view>
</body>
</html>



manager bean 如下:
package test;


import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class ChildDAOImp extends HibernateDaoSupport implements ChildDAO {
	private static final Log log = LogFactory.getLog(Child.class);
	

	/* (non-Javadoc)
	 * @see test.ChildDAO#getChild(java.lang.Integer)
	 */
	public Child getChild(Integer id){
		return (Child)getHibernateTemplate().get(test.Child.class, id);
	}

	/* (non-Javadoc)
	 * @see test.ChildDAO#loadChild(java.lang.Integer)
	 */
	public Child loadChild(Integer id){
		return (Child)getHibernateTemplate().load(test.Child.class, id);
	}
	
	/* (non-Javadoc)
	 * @see test.ChildDAO#getAllParents()
	 */
	public List getAllParents(){
		try {
			String queryString = "from Parent";
			return getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw re;
		}
	}

	/* (non-Javadoc)
	 * @see test.ChildDAO#getAllParents()
	 */
	public List getAllParentbs(){
		try {
			String queryString = "from Parentb";
			return getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw re;
		}
	}
	
	
	/* (non-Javadoc)
	 * @see test.ChildDAO#getParentsMapList()
	 */
	public Map getParentsMapList(){
		Map options=new LinkedHashMap();
		options.put("请选择..", "");
		List parents= getAllParents();
        for (Iterator it = parents.iterator(); it.hasNext();) {
        	Parent option = (Parent) it.next();
        	options.put(option.getName(), option.getId().toString());
        }
		return options;		
	}

	/* (non-Javadoc)
	 * @see test.ChildDAO#getParentsMapList()
	 */
	public Map getParentbsMapList(){
		Map options=new LinkedHashMap();
		options.put("请选择..", "");
		List parents= getAllParentbs();
        for (Iterator it = parents.iterator(); it.hasNext();) {
        	Parentb option = (Parentb) it.next();
        	options.put(option.getName(), option.getCode());
        }
		return options;		
	}

	
	
	public void saveOrUpdate(Child chd){
		getHibernateTemplate().saveOrUpdate(chd);
	}
	
	public void merge(Child chd){
		getHibernateTemplate().merge(chd);
	}
	public void refresh(Child chd){
		getHibernateTemplate().refresh(chd);
	}
	public void save(Child chd){
		getHibernateTemplate().save(chd);
	}
	
	public void persist(Child chd){
		getHibernateTemplate().persist(chd);
	}
	public void update(Child chd){
		getHibernateTemplate().update(chd);
	}

	public void replicate(Child chd){
		getHibernateTemplate().replicate(chd, org.hibernate.ReplicationMode.OVERWRITE);
	}
}
2 楼 movingboy 2007-08-15  
建议把如何设置Child实例的parent属性的代码也贴出来
1 楼 songxh2 2007-08-15  
上面代码乱了,再附上:

1.保存对象含单向多对一关系。
被测试对象test.Child的hbm:

<hibernate-mapping>
<class name="test.Child" table="app_child" schema="dbo">
<id name="id" column="ChildId" type="integer">
<generator class="identity"></generator>
</id>
<property name="name" type="string">
<column name="name" length="50" not-null="true"></column>
</property>
<many-to-one name="parent" class="test.Parent" column="ParentID" outer-join="true" update="true">
</many-to-one>
<many-to-one name="parentb" class="test.Parentb" column="codea" outer-join="true">
</many-to-one>
</class>
</hibernate-mapping>


2.被关联对象test.Parent如下hbm:
<hibernate-mapping>
<class name="test.Parent" table="app_parent" schema="dbo">
<id name="id" column="ParentId" type="integer"><generator class="identity"></generator></id>
<property name="name" type="string">
<column name="name" length="50" not-null="true" unique="true"></column>
</property>
<!-- 
<set name="children" inverse="false">
<key column="ParentID"/>
<one-to-many class="test.Child"/>
</set>
 -->
</class>
</hibernate-mapping>


3.操作页面jsf。Backingbean如下:
package test;

import net.xerllent.system.web.BasePage;
import org.springframework.dao.DataAccessException;
import java.util.Map;
public class TestForm extends BasePage {
	private Child child;
	private ChildDAO childDAO;
	
	public Child getChild() {
		
		if(child==null){
//			child=(Child)childDAO.getChild(new Integer(3));
			child=(Child)childDAO.loadChild(new Integer(3));
			if(child==null) {
				child=new Child();
			}
		}
		return child;
	}

	public void setChild(Child child) {
		this.child = child;
	}

	public void setChildDAO(ChildDAO childDAO) {
		this.childDAO = childDAO;
	}
	
	
	
	public String merge() {
		try {
			childDAO.merge(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}

	public String persist() {
		try {
			childDAO.persist(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}

	public String refresh() {
		try {
			childDAO.refresh(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}

	public String replicate() {
		try {
			childDAO.replicate(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}

	public String save() {
		try {
			childDAO.save(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}

	public String saveOrUpdate() {
		try {
			childDAO.saveOrUpdate(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}

	public String update() {
		try {
			childDAO.update(child);
			return "success";
		} catch (RuntimeException e) {
			return "success";
		}
	}	public Map getDictParents(){
		return childDAO.getParentsMapList();
	}
	public Map getDictParentbs(){
		return childDAO.getParentbsMapList();
	}
}

相关推荐

    (4)Hibernate中的many-to-one和one-to-many关系

    本话题主要探讨两种基本的关系映射类型:many-to-one(多对一)和one-to-many(一对多)。这两种关系映射是数据库中常见的关联类型,理解和掌握它们对于开发高质量的Java应用至关重要。 1. many-to-one关系 many-to...

    Hibernate one-to-many / many-to-one关系映射

    "Hibernate one-to-many / many-to-one关系映射"是两个基本的关系类型,用于表示实体间的关联。在这个主题中,我们将深入探讨这两种关系映射的原理、配置和实际应用。 一、一对一(one-to-one)与一对多(one-to-...

    hibernate many-to-many级联保存,级联更新,级联删除

    在Java的持久化框架Hibernate中,Many-to-Many关系是一种常见的数据库表之间的关联方式,它表示一个实体可以与多个其他实体进行关联,反之亦然。本文将深入探讨如何在Hibernate中处理Many-to-Many关系的级联保存、...

    hibernate many-to-one(多对一)及 cascade(级联).doc

    在Hibernate中,可以通过 `&lt;many-to-one&gt;` 或者 `&lt;one-to-many&gt;` 标签中的 `cascade` 属性来指定这种行为。 #### 代码示例解析 在提供的代码示例中,`&lt;many-to-one&gt;` 标签中包含了 `cascade` 属性的注释示例,但是...

    Hibernate中many-to-one关系的编写_远航的水手

    Hibernate中many-to-one关系的编写_远航的水手

    Hibernate中many-to-one关系的编写_远航的水手.htm

    Hibernate中many-to-one关系的编写_远航的水手.htm

    Hibernate Mapping Many-to-One 实例 内附源代码及附件下载

    对于`Department`,映射文件中会有一个`&lt;class&gt;`标签,其中包含`&lt;set&gt;`标签来定义员工集合,并且使用`&lt;many-to-many&gt;`或`&lt;one-to-many&gt;`标签来映射与`Employee`的关系。对于`Employee`,我们使用`&lt;class&gt;`标签,并在...

    hibernate one-to-one 一对一唯一外键关联映射_单向 and 双向

    在上面的配置中, `&lt;many-to-one&gt;` 标签指定了Person实体与IdCard实体之间的一对一唯一外键关联关系,其中unique="true"指定了多的一端的多重性为一。 Hibernate 一对一唯一外键关联映射的应用 在实际应用中,一对...

    hibernate jar包:hibernate-commons-annotations-4.0.1.Final.jar等

    hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-4.1.12.Final.jar hibernate-jpa-2.0-api-1.0.1.Final.jar ...

    hibernate-jpa-2.1-api-1.0.2.Final-API文档-中文版.zip

    赠送jar包:hibernate-jpa-2.1-api-1.0.2.Final.jar; 赠送原API文档:hibernate-jpa-2.1-api-1.0.2.Final-javadoc.jar; 赠送源代码:hibernate-jpa-2.1-api-1.0.2.Final-sources.jar; 赠送Maven依赖信息文件:...

    hibernate-configuration-3.0.dtd、hibernate-mapping-3.0.dtd

    《深入理解Hibernate配置与映射:hibernate-configuration-3.0.dtd与hibernate-mapping-3.0.dtd解析》 在Java世界里,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。而`hibernate-...

    hibernate-jpa-2.1-api-1.0.2.Final-API文档-中英对照版.zip

    赠送jar包:hibernate-jpa-2.1-api-1.0.2.Final.jar; 赠送原API文档:hibernate-jpa-2.1-api-1.0.2.Final-javadoc.jar; 赠送源代码:hibernate-jpa-2.1-api-1.0.2.Final-sources.jar; 赠送Maven依赖信息文件:...

    Hibernate Tutorial 04 (Many-to-one and One-to-one Association

    #### 一、多对一关联(Many-to-One) 在本章中,我们将探讨如何在 Hibernate 中处理多对一关联。这种关联类型非常常见,在许多应用中都会遇到。例如,在一个在线书店应用中,每本书都与一个出版商关联,而一个出版...

    Hibernate-one-to-many

    本文将深入探讨Hibernate中一对多(One-to-Many)关系的处理方式,特别是通过外键映射和inverse属性的应用场景。 #### 一对多关系概念 一对多关系在数据库设计中非常常见,它指的是一个实体可以与多个其他实体关联...

    Hibernate实现many-to-many的映射关系

    在本文中,我们将深入探讨如何使用Hibernate来实现多对多(many-to-many)的映射关系。 首先,多对多映射关系通常涉及到两个实体类之间的关联,例如在学生选课的例子中,学生(Student)和课程(Course)之间存在多...

    Hibernate Many-To-Many Mapping Annotations

    在Java的持久化框架Hibernate中,Many-to-Many映射是一种常见的关系模型,它用于表示两个实体类之间多对多的关系。在这个主题中,我们将深入探讨如何使用注解来实现这种映射,以及其背后的数据库原理和实际应用。 ...

    hibernate:one-to-one

    hibernate:one-to-one 的学习小经验

    Hibernate应用例子many-to-many

    本示例将详细讲解如何在Hibernate中实现多对多(many-to-many)的关系映射。 在数据库设计中,多对多关系是指两个实体之间存在多个关联,比如学生和课程的关系,一个学生可以选修多门课程,一门课程也可以被多个...

    hibernate学习5之one-to-many双向关联.docx

    而`Classes.hbm.xml`则使用了`&lt;set&gt;`和`&lt;one-to-many&gt;`元素,表示班级对象包含一个学生集合,且每个学生都有对应的`id`。 在处理这种关联关系时,需要注意的是效率问题。由于Hibernate默认会在"一"端更新关联关系,...

    hibernate-jpa-2.1-api-1.0.0.final-sources.jar

    hibernate-jpa-2.1-api-1.0.0.final-sources.jar 源码 hibernate-jpa-2.1-api-1.0.0.final-sources.jar 源码

Global site tag (gtag.js) - Google Analytics