2012-05-03 49 views
2

我在網上看到了很多使用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的新版本中這是不可能的?

回答

1

問題是Hibernate的已發佈一項更新,而不是INSERT命令的companydocs對象。這是因爲如果對象的主鍵是null,那麼Hibernate將會執行插入操作,如果它不是null,它將執行更新,在我的情況下,因爲我在下面的實現類中設置了鍵,它正在執行更新。

原始代碼

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());  
    } 

新代碼

if(cd == null) 
    { 
    cd = new CompanyDocs();//no-arg constructor 
    c.setCompanyDocs(cd); 
    cd.setCompany(c); 
    LOG.info("CompanyDocs object created new :- " + cd); 
    companyDao.storeCompanyDocs(cd); 
    LOG.info("CompanyDocs object stored :- " + cd.getDocsid());  
    } 

漂亮的工作!

我發現這個鏈接有用的修復此問題

Hibernate StaleStateException

1

@PrimaryKeyJoinColumn應該只在可選的一面使用,所以刪除@PrimaryKeyJoinColumn這是Company註釋。

此外,@OneToOnemappedBy屬性應引用標記在@OneToOne上的實體的屬性名稱。因此,它應該是:

@OneToOne(fetch = FetchType.LAZY, mappedBy = "company") 
+0

很抱歉,在這個問題一個錯字,該屬性的mappedBy是公司。此外,我也刪除了公司方面的@PrimaryKeyJoinColumn,但這並不重要。不過,我終於解決了這個問題,請看下面的答案。 – Angela

+0

就是這樣記錄的:「@PrimaryKeyJoinColumn只能用在可選的一面」。我對OneToOne映射也有一些問題 – Cris

+0

嗨克里斯,這只是從我自己的演繹和觀察。顧名思義,'@ PrimaryKeyJoinColumn'表示當前表的PK將對另一個表具有FK約束。因此,如果在另一個表中沒有記錄,我們不能在當前表中創建記錄,因爲當前表中沒有可用於記錄PK的值。因此,當前表是可選的一面 –

相關問題