开发者

Grails - how to save a domain object inside a Service?

I have a service and inside one of the functions i'm creating a domain object and trying to save i开发者_JAVA百科t.

when it gets to the save part, i get the error

No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

What do i need to do in order to save a domain object inside of a service. everything on the internet makes it look like this should just work....

Edit:

additional details: I stumbled across this post

Hibernate session in threads

which is a similar scenario. My service is getting called by a 3rd party API.

Edit:

I'm not explaining this very well. Here is more complete code

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
            }
        }
 }
}

the 3rd party API is calling historicalData several times. With the above code, it is saving the first record, but then on the 2nd record i'm getting the error:

Could not open Hibernate Session; nested exception is org.hibernate.SessionException: Session is closed!

Edit:

so reading up on this more i think i understand what is happening.

a hibernate session is usually injected into the Service when called from the controller.

Because historicalData is being called from a 3rd party app and not via a controller, no hibernate session is getting injected into the service so it complains that the Session is closed.

So I think the real question may be, if a service is not called from a controller, how do i create a new hibernate session in order to save a grails domain model object (i.e. HistoricalContractData).

As can be seen above, withNewSession is not working. Should i be using a SessionFactory like so ?

(can't post link to source because stack overflow doesn't like it)

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
    }
}

I kind of tried this but don't understand how to use the session object in order to save the HistoricalContractData object.


Service methods should be transactional, and have a session, by default. If they are not, you are probably not following Grails conventions somehow:

  1. Is your service in the services directory of grails-app?
  2. Does your service name/file end with 'Service'?
  3. Did you make the service or service method itself not transactional somehow?
  4. Are you not invoking the service from a controller?
  5. Are you using dependency injection to get your services into where-ever you use them?

That said, you can always create a transaction by doing

AnyDomainObject.withTransaction{txStatus->
// do stuff like save here
}

or create a new session with

AnyDomainObject.withNewSession{session->
// do stuff here
}

the code you have does not have the 'arrow' that is necessary for closures.

EDIT, for you updates, you should checkout

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

on how to use the session. Basically, you should be able to do just

session.save(hcd)

Also, you might be able to do hcd.save() like normal in grails after you call the sessionFactory.getCurrentSession() -- the reason I think this might work is that method should create a new session and bind it to the current thread via threadlocal.


You need to specify a transaction context for your service. Make sure your Grails services are done this way.

Another Grails service link:

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜