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 errorNo 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 threadswhich 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 codeimport 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:
- Is your service in the services directory of grails-app?
- Does your service name/file end with 'Service'?
- Did you make the service or service method itself not transactional somehow?
- Are you not invoking the service from a controller?
- 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
精彩评论