Grails - 如何在服务中保存域对象?

时间:2010-12-31 22:45:45

标签: hibernate session grails service grails-domain-class

我有一个服务,其中一个函数我正在创建一个域对象并试图保存它 当它到达保存部分时,我收到错误

  

没有Hibernate Session绑定到线程,   和配置不允许   在这里创建非交易的

为了在服务中保存域对象,我需要做什么。互联网上的一切都让它看起来像是应该工作....

修改
额外细节: 我偶然发现了这篇文章 Hibernate session in threads

这是一个类似的场景。我的服务正在被第三方API调用。

修改
我不是很好解释。这是更完整的代码

import org.springframework.beans.factory.InitializingBean
import com.ib.client.EWrapper;


class BrokerService implements InitializingBean, EWrapper{

    static transactional = true

    private EClientSocket m_client
    private boolean m_disconnectInProgress = false

    void afterPropertiesSet(){
       // this.setting = grailsApplication1.config.setting
       m_client = new EClientSocket(this)
       m_disconnectInProgress = false

       connect()
    }


    def boolean connect() {
        m_client.eConnect()
        if (m_client.isConnected())
            return true

        return false
 }

    def void historicalData(int reqId, String date, double open,
   double high, double low, double close, int volume, int count,
   double WAP, boolean hasGaps)
    {   
        HistoricalContractData.withNewSession{session->
            println ' just before object create'
            def hcd = new sbi.investments.HistoricalContractData()
            hcd.hc_id = reqId
            hcd.data_date = new Date().parse('yyyyMMdd', date.replace('finished-', ''))
            hcd.open = open
            hcd.high = high
            hcd.low = low
            hcd.close = close
            hcd.volume =volume
            hcd.trade_count =count
            hcd.wap = WAP
            hcd.has_gaps = hasGaps.toString()
            println ' just before save'
            hcd.save()

            if(hcd.hasErrors()){
                println '=========== ERROR! ============'
                println hcd.errors
            }
        }
 }
}

第三方API多次调用historicalData。使用上面的代码,它保存了第一条记录,但是在第二条记录上我得到了错误:

  

无法打开Hibernate Session;   嵌套异常是   org.hibernate.SessionException:   会议已结束!

修改
所以阅读更多我认为我明白发生了什么 当从控制器调用时,通常会向服务中注入一个休眠会话 因为历史数据是从第三方应用程序而不是通过控制器调用的,所以没有将hibernate会话注入服务,因此它会抱怨会话已关闭。

所以我认为真正的问题可能是,如果没有从控制器调用服务,我如何创建一个新的hibernate会话以保存grails域模型对象(即HistoricalContractData)。
从上面可以看出,withNewSession不起作用。我应该像这样使用SessionFactory吗? (无法发布链接到源代码,因为堆栈溢出不喜欢它)

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class YourService  {

    SessionFactory sessionFactory // set by Dependency Injection

    public void yourMethod() {
        Session session = sessionFactory.getCurrentSession();
        // do something with session
    }
}

我试过这种方法,但是不明白如何使用会话对象来保存HistoricalContractData对象。

2 个答案:

答案 0 :(得分:4)

默认情况下,服务方法应该是事务性的,并且具有会话。如果不是,你可能不会以某种方式遵循Grails惯例:

  1. 您的服务是否位于grails-app的服务目录中?
  2. 您的服务名称/文件是否以“服务”结尾?
  3. 您是否以某种方式使服务或服务方法本身不是交易?
  4. 您是否未从控制器调用该服务?
  5. 您是否正在使用依赖注入将服务引入您使用它们的位置?
  6. 也就是说,您可以通过

    创建交易
    AnyDomainObject.withTransaction{txStatus->
    // do stuff like save here
    }
    

    或使用

    创建新会话
    AnyDomainObject.withNewSession{session->
    // do stuff here
    }
    

    您拥有的代码没有闭包所需的“箭头”。

    编辑,对于您的更新,您应该结帐

    http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

    关于如何使用会话。基本上,你应该能够做到

    session.save(hcd)
    

    另外,你可能能够像grails 那样正常地执行hcd.save()你调用sessionFactory.getCurrentSession() - 我认为这个的原因可能有用的是该方法应创建一个新会话并通过threadlocal将其绑定到当前线程。

答案 1 :(得分:0)

您需要为服务指定交易上下文。确保您的Grails服务已完成this way

另一个Grails服务链接:

http://www.grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html