我在網上看到了很多使用Hibernate註釋進行一對一共享主鍵映射的例子/教程。然而,在我看到的所有例子中,似乎映射不能是可選的,或者如果它是可選的,它不能在主鍵上。我有以下情況,在公司表 和CompanyDocs表之間有一對一的主鍵映射。 CompanyDocs表是一個弱實體,即,雖然存在公司對象,但從一開始就不需要鏈接一個CompanyDocs實體,但可能稍後會創建該實體。Hibernate中的一對一共享主鍵映射可以爲可選/空嗎?
公司對象由外部應用程序創建並保存,但是使用Hibernate應用程序更新。 這是我有。(請注意,這是不實際的例子)
Company table
- companyid (Pk)
- name
- desc
- test1
- test2
CompanyDocs table
- docsid (Pk) (Fk)
- detail1
- detail2
- detail3
模型類
Company.java
@Entity
@Table(name = "company", schema = "public")
public class Company implements java.io.Serializable {
private String companyid
private CompanyDocs companydocs;
@Id
@Column(name = "companyid", unique = true, nullable = false, length = 20)
public String getCompanyid() {
return this.companyid;
}
public void setCompanyid(String companyid) {
this.companyid = companyid;
}
@OneToOne(fetch = FetchType.LAZY, mappedBy = "companydocs")
@NotFound(action = NotFoundAction.IGNORE)
@PrimaryKeyJoinColumn(name = "companyid", referencedColumnName = "docsid")
public CompanyDocs getCompanydocs() {
return this.companydocs;
}
public void setCompanydocs(CompanyDocs companydocs) {
this.companydocs = companydocs;
}
}
CompanyDocs.java
@Entity
@Table(name = "companydocs", schema = "public")
public class CompanyDocs implements java.io.Serializable {
private String docsid;
private Company company;
@GenericGenerator(name = "generator", strategy = "foreign", parameters =
@Parameter(name = "property", value = "company"))
@Id
@GeneratedValue(generator = "generator")
@Column(name = "docsid", unique = true, nullable = false, length = 20)
public String getDocsid() {
return this.docsid;
}
public void setDocsid(String docsid) {
this.docsid = docsid;
}
@PrimaryKeyJoinColumn(name = "docsid", referencedColumnName = "companyid")
@OneToOne(fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE)
public Company getCompany() {
return this.company;
}
public void setCompany(Company company) {
this.company = company;
}
CompanyDAOImpl.java
public Company getCompany(String companyid) {
Criteria c = sessionFactory.getCurrentSession().createCriteria(Company.class)
.add(Restrictions.eq("companyid", companyid));
try {
return (Company) c.list().get(0);
}
catch(IndexOutOfBoundsException e) {
logger.info("GetCompany threw exception " +e);
return null;
}
}
public void storeCompany(Company c) {
sessionFactory.getCurrentSession().saveOrUpdate(c);
}
public void storeCompanyDocs(CompanyDocs cd) {
sessionFactory.getCurrentSession().saveOrUpdate(cd);
}
public CompanyDocs getCompanyDocs(String companyid) {
try{
Criteria c = sessionFactory.getCurrentSession()
.createCriteria(CompanyDocs.class).add(Restrictions.eq("companyid", companyid));
logger.info("getCompanyDocsreturned"+c.list().get(0));
return (CompanyDocs)c.list().get(0);
}catch(IndexOutOfBoundsException e){
logger.info("getCompanyDocs threw exception " +e);
return null;
}
}
Compan yServiceImpl.java
@Transactional(propagation = Propagation.REQUIRED, readOnly= false,
noRollbackFor=IllegalArgumentException.class)
@ExceptionHandler(NullPointerException.class)
public CompanyResponse updateCompany(Service parameters) throws SOAPException {
LOG.info("In updateCompany");
Company c = companyDao.getCompany(parameters.getId());
//CompanyDocs cd = companyDao.getCompanyDocs(parameters.getId());
CompanyDocs cd = c.getCompanyDocs();
LOG.info("CompanyDocs object is:- " + cd);
if(cd == null)
{
cd = new CompanyDocs(parameters.getId());
c.setCompanyDocs(cd);
cd.setCompany(c);
LOG.info("CompanyDocs object created new :- " + cd);
companyDao.storeCompanyDocs(cd);
LOG.info("CompanyDocs object stored :- " + cd.getDocsid());
}
c.setDetail1();
c.setDetail2();
c.setDetail3();
.............
companyDao.storeCompany(c)
LOG.info("Stored Company");
LOG.info("CompanyService Response Return------:")
return new CompanyResponse();
}
我的日誌文件打印此。
2012-05-02 22:57:18,951 INFO [au.com.CompanyServiceImpl] - <In updateCompany>
2012-05-02 22:57:18,975 INFO [au.com.CompanyDAOImpl] - <getCompany returned
[email protected]>[au.com.CompanyServiceImpl] - <CompanyDocs object is:- null>
2012-05-02 22:57:18,991 INFO [au.com.CompanyServiceImpl] - <CompanyDocs object
created new :- [email protected]>
2012-05-02 22:57:18,995 INFO [au.com.CompanyServiceImpl] - <CompanyDocs object
updated :- CO12345>
2012-05-02 22:57:19,338 INFO [au.com.CompanyDAOImpl] - <Stored Company >
2012-05-02 22:57:19,338 INFO [au.com.CompanyServiceImpl] - <CompanyService
Response Return------:>
2012-05-02 22:57:19,498 ERROR [org.hibernate.jdbc.AbstractBatcher] - <Exception
executing batch: >
org.hibernate.StaleStateException: Batch update returned unexpected row count from
update [0]; actual row count: 0; expected: 1 at
org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
at
org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:68)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener
.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.
onFlush(DefaultFlushEventListener.java:27)
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:656)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.
processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager
.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport
.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor
.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation
.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.
invoke(JdkDynamicAopProxy.java:202)
at $Proxy28.login(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.
invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.cxf.service.invoker.AbstractInvoker.
performInvocation(AbstractInvoker.java:173)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:89)
at org.apache.cxf.jaxws.JAXWSMethodInvoker.invoke(JAXWSMethodInvoker.java:60)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:75)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.
run(ServiceInvokerInterceptor.java:58)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at org.apache.cxf.workqueue.SynchronousExecutor.
execute(SynchronousExecutor.java:37)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.
handleMessage(ServiceInvokerInterceptor.java:106)
at org.apache.cxf.phase.PhaseInterceptorChain.
doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.transport.ChainInitiationObserver.
onMessage(ChainInitiationObserver.java:113)
at org.apache.cxf.transport.servlet.ServletDestination.
invoke(ServletDestination.java:97)
at org.apache.cxf.transport.servlet.ServletController.
invokeDestination(ServletController.java:461)
at org.apache.cxf.transport.servlet.ServletController.
invoke(ServletController.java:188)
at org.apache.cxf.transport.servlet.AbstractCXFServlet.
invoke(AbstractCXFServlet.java:148)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.
handleRequest(AbstractHTTPServlet.java:179)
at org.apache.cxf.transport.servlet.
AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:103)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.
service(AbstractHTTPServlet.java:159)
at org.apache.catalina.core.ApplicationFilterChain.
internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.
doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.
invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.
invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.
invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.
process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:662)
2012-05-02 22:57:19,501
ERROR [org.hibernate.event.def.AbstractFlushingEventListener]
- <Could not synchronize database state with session>
我已經嘗試使用@non註釋,可選= false/true,也嘗試使用單向映射並使用條件加載companydocs對象。但是看起來Hibernate總是爲一個現有公司除了一個CompanyDocs對象。
奇怪的是,當我們使用早期版本的hibernate並且使用映射文件而不是註釋時,這個功能很好用。這是一個共享密鑰映射,但單向,因此公司hbm文件沒有映射CompanyDocs對象。 我使用hibernate 3.3.1.GA.jar進行註釋。有沒有我在我身邊做過錯的事情,或者在Hibernate的新版本中這是不可能的?
很抱歉,在這個問題一個錯字,該屬性的mappedBy是公司。此外,我也刪除了公司方面的@PrimaryKeyJoinColumn,但這並不重要。不過,我終於解決了這個問題,請看下面的答案。 – Angela
就是這樣記錄的:「@PrimaryKeyJoinColumn只能用在可選的一面」。我對OneToOne映射也有一些問題 – Cris
嗨克里斯,這只是從我自己的演繹和觀察。顧名思義,'@ PrimaryKeyJoinColumn'表示當前表的PK將對另一個表具有FK約束。因此,如果在另一個表中沒有記錄,我們不能在當前表中創建記錄,因爲當前表中沒有可用於記錄PK的值。因此,當前表是可選的一面 –