Как я могу включить получение сеанса / транзакции в ленивый инициатор отношений в Squeryl? - PullRequest
2 голосов
/ 28 января 2011

Я пытаюсь реализовать отношение «один ко многим», используя Squeryl, и следуя инструкциям на их сайте .

В документации приведен следующий пример:

object SchoolDb extends Schema {    
  val courses = table[Course]    
  val subjects = table[Subject]      
  val subjectToCourses =
    oneToManyRelation(subjects, courses).
    via((s,c) => s.id === c.subjectId)  
}

class Course(val subjectId: Long) extends SchoolDb2Object {    
  lazy val subject: ManyToOne[Subject] = SchoolDb.subjectToCourses.right(this)
}

class Subject(val name: String) extends SchoolDb2Object {    
  lazy val courses: OneToMany[Course] = SchoolDb.subjectToCourses.left(this)
}

Я считаю, что любые вызовы Course.subject или Subject.courses должны быть включены в транзакцию. Тем не менее, одна из моих целей при использовании ORM - скрыть эти детали от абонентов. Поэтому я не хочу, чтобы вызывающий код обернул вызов этих полей в транзакции.

Похоже, что если я изменю пример, чтобы обернуть ленивую функцию инициализации в транзакции, вот так:

class Subject(val name: String) extends SchoolDb2Object {    
  lazy val courses: OneToMany[Course] = {
    inTransaction {
      SchoolDb.subjectToCourses.left(this)
    }
}

Я получаю следующее исключение:

Exception in thread "main" java.lang.RuntimeException: no session is bound to current thread, a session must be created via Session.create 
and bound to the thread via 'work' or 'bindToCurrentThread'
    at scala.Predef$.error(Predef.scala:58)
    at org.squeryl.Session$$anonfun$currentSession$1.apply(Session.scala:111)
    at org.squeryl.Session$$anonfun$currentSession$1.apply(Session.scala:111)
    at scala.Option.getOrElse(Option.scala:104)
    at org.squeryl.Session$.currentSession(Session.scala:110)
    at org.squeryl.dsl.AbstractQuery.org$squeryl$dsl$AbstractQuery$$_dbAdapter(AbstractQuery.scala:116)
    at org.squeryl.dsl.AbstractQuery$$anon$1.<init>(AbstractQuery.scala:120)
    at org.squeryl.dsl.AbstractQuery.iterator(AbstractQuery.scala:118)
    at org.squeryl.dsl.DelegateQuery.iterator(DelegateQuery.scala:9)

Но, как я уже сказал, если я включаю вызывающего в транзакцию, то все работает.

Итак, как я могу инкапсулировать тот факт, что этот объект поддерживается базой данных в самом объекте?

1 Ответ

1 голос
/ 28 января 2011

Я полагаю, вы получили эту ошибку при вызовах объекта курсов?

Я не очень много знаю о том, как работает Squeryl, но я считаю, что OneToMany [Course] - это живой объект.Это означает, что вызовам объекта курсов требуется сеанс, поскольку любой вызов может лениво идти в базу данных для получения данных.

Способ организации этого зависит от того, какое приложение вы используете.В веб-приложении часто имеет смысл добавить фильтр (первая точка входа) для запуска и остановки транзакции.В клиенте с графическим интерфейсом, скажем, в Swing-приложении, это хорошее решение для запуска транзакции в точке, где вы получаете взаимодействие с пользователем.Таким образом, вы получаете транзакции, которые не слишком длинные, а также растягивают вызовы, которые, как вы ожидаете, будут выполняться атомарно (полностью или не полностью).

...