我正在尝试使用Squeryl实现一对多关系,并遵循instructions on their site。
文档提供了以下示例:
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的目标之一是隐藏呼叫者的这些细节。因此,我不希望调用代码必须在事务中包含对这些字段的调用。
似乎我修改了示例以在事务中包装惰性init函数,如下所示:
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)
但是,就像我说的,如果我在一个事务中包装调用者,那么一切正常。
那么,我如何封装这个对象由对象本身的数据库支持的事实呢?
答案 0 :(得分:1)
我假设你在课程对象的调用中遇到这个错误?
我不太了解Squeryl是如何工作的,但我相信OneToMany [Course]是一个实时对象。这意味着对课程对象的调用需要一个会话,因为任何调用可能会懒洋洋地进入数据库以获取数据。
如何组织这取决于您使用的应用程序类型。在Web应用程序中,添加过滤器(第一个入口点)以启动和停止事务通常是有意义的。在GUI客户端,比如一个swing应用程序,它是一个很好的解决方案,可以在您收到用户交互时启动事务。这样你就可以获得不长的交易,也可以延伸你希望以原子方式执行的调用(完全或根本不执行)。