Grails — как сохранить объект домена внутри службы?

У меня есть служба, и внутри одной из функций я создаю объект домена и пытаюсь его сохранить.
когда он доходит до части сохранения, я получаю сообщение об ошибке

Сессия Hibernate не привязана к потоку, и конфигурация не позволяет создавать здесь нетранзакционную сессию.

Что мне нужно сделать, чтобы сохранить объект домена внутри службы. все в интернете делает вид, что это должно просто работать....

Изменить:
дополнительные сведения: я наткнулся на этот пост
Спящий сеанс в тредах

что аналогичный сценарий. Мой сервис вызывается сторонним 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 несколько раз вызывает historyData. С приведенным выше кодом он сохраняет первую запись, но затем во второй записи я получаю сообщение об ошибке:

Не удалось открыть сеанс гибернации; вложенным исключением является org.hibernate.SessionException: сеанс закрыт!

Редактировать:
поэтому, читая об этом больше, я думаю, что понимаю, что происходит.
сеанс гибернации обычно внедряется в Службу при вызове из контроллера.
Поскольку historyData является при вызове из стороннего приложения, а не через контроллер, сеанс гибернации не внедряется в службу, поэтому он жалуется, что сеанс закрыт.

Поэтому я думаю, что реальный вопрос может заключаться в том, что если служба не вызывается из контроллера, как мне создать новый сеанс гибернации, чтобы сохранить объект модели предметной области 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.


person w--    schedule 31.12.2010    source источник


Ответы (2)


Методы службы должны быть транзакционными и иметь сеанс по умолчанию. Если это не так, возможно, вы каким-то образом не следуете соглашениям Grails:

  1. Ваш сервис находится в каталоге сервисов приложения grails?
  2. Имя/файл вашей службы заканчивается на «Сервис»?
  3. Вы каким-то образом сделали сам сервис или метод сервиса не транзакционным?
  4. Вы не вызываете службу из контроллера?
  5. Используете ли вы внедрение зависимостей, чтобы ваши сервисы использовались везде, где бы вы их ни использовали?

Тем не менее, вы всегда можете создать транзакцию, выполнив

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)

Кроме того, вы можете выполнить hcd.save() как обычно в Grails после вызова sessionFactory.getCurrentSession() -- причина, по которой я думаю, что это может сработать, заключается в следующем. этот метод должен создать новый сеанс и привязать его к текущему потоку через threadlocal.

person hvgotcodes    schedule 31.12.2010
comment
@hvtgotcodes спасибо. Я думаю, что следую большинству этих условностей. # 4 нет, потому что функция historyData в службе вызывается сторонним API (другим приложением). - person w--; 01.01.2011
comment
@w- как другое приложение получает ваши услуги? Если он вызывает его через веб-запрос (например, REST API), то у вас должен быть контроллер перед службой. Неважно, добавление стрелки, как я показал, должно помочь. - person hvgotcodes; 01.01.2011
comment
@hvgotcodes, как вы можете видеть выше, сервис реализует EWrapper, который представляет собой интерфейс, предоставляемый сторонним API. HistoricalData регистрируется как функция обратного вызова, которую другое приложение использует для предоставления мне данных. поэтому служба не вызывается через HTTP-запрос от контроллера. это просто... вызывается напрямую. Это помогает прояснить? - person w--; 02.01.2011
comment
@w- Является ли HistoricalContractData классом модели предметной области? - person hvgotcodes; 02.01.2011
comment
@hvtgotcodes да, это так. Поэтому, читая об этом больше, я думаю, что понимаю, что может происходить. пожалуйста, смотрите обновленные комментарии выше и дайте мне знать, если я полностью не в курсе. благодаря. - person w--; 02.01.2011
comment
@w-, вы можете сделать BrokerService BrokerService? - person hvgotcodes; 02.01.2011
comment
@hvtgotcodes я изменил это, но не повезло. Я все еще получаю сообщение об ошибке Не удалось открыть сеанс гибернации; вложенным исключением является org.hibernate.SessionException: сеанс закрыт! при попытке сохранить вторую запись. - person w--; 02.01.2011
comment
@w--, вы сохраняете более одного объекта? Это не должно быть проблемой в любом случае. На этом этапе вы должны опубликовать определение службы и (новый) код, который у вас есть. Вы также можете попробовать irc #grails на freenode, чтобы получить помощь в реальном времени. - person hvgotcodes; 02.01.2011
comment
@hvtgotcodes да, historyData вызывается более одного раза, поэтому я сохраняю более одного объекта. самая последняя версия кода находится в вопросе. - person w--; 02.01.2011
comment
@w-- я не вижу, где вы создаете сеанс в своем коде (если только вы все еще не используете withNewSession). Я тоже не вижу двух сохранений. Можете ли вы изменить свой метод sig на «public void historyData (...)» вместо def.... - person hvgotcodes; 02.01.2011
comment
@w-- это библиотека, которую вы используете? institutions.interactivebrokers.com/php/apiguide/ Я не думаю, что HistoricalContractData является объектом предметной области Grails — похоже, это класс Java. Попробуйте взять реальный класс домена в своем приложении (один в grails-app/domain) и использовать withNewSession. - person hvgotcodes; 03.01.2011
comment
@w-- предполагая, что мои два комментария выше не помогают, попробуйте пока отключить инициализирующий компонент для объявления класса. ознакомьтесь с главой 8 grails.org/doc/latest — этот интерфейс не используется. - person hvgotcodes; 03.01.2011

Вам необходимо указать контекст транзакции для вашего сервиса. Убедитесь, что ваши службы Grails работают таким образом.

Ссылка на другой сервис Grails:

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

person duffymo    schedule 31.12.2010
comment
вы имеете в виду сферу услуг? мой сервис одноэлементный. не могли бы вы указать мне на некоторые примеры или документы, пожалуйста? Благодарность - person w--; 01.01.2011
comment
Не могли бы вы уточнить, что вы имеете в виду под этим? Я изначально следовал этому руководству, чтобы создать свой сервис, но документация по этой теме кажется скудной. - person w--; 01.01.2011
comment
Невозможно быть более конкретным, не видя весь ваш код. Честно говоря, я не знаю, что я хочу тратить время. Я выхожу сегодня вечером! - person duffymo; 01.01.2011
comment
достаточно честно. К счастью, я также могу сказать, что выхожу сегодня вечером. Я опубликую более полный код завтра или что-то в этом роде. С новым годом! - person w--; 01.01.2011