Orm 如何将会话/事务获取封装到Squeryl中关系的lazy init中?
我正在尝试使用Squeryl实现一对多关系,并遵循以下步骤 本文档给出了以下示例:Orm 如何将会话/事务获取封装到Squeryl中关系的lazy init中?,orm,scala,squeryl,Orm,Scala,Squeryl,我正在尝试使用Squeryl实现一对多关系,并遵循以下步骤 本文档给出了以下示例: object SchoolDb extends Schema { val courses = table[Course] val subjects = table[Subject] val subjectToCourses = oneToManyRelation(subjects, courses). via((s,c) => s.id === c.s
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的目标之一是对调用方隐藏这些细节。因此,我不希望调用代码必须在事务中包装对这些字段的调用
如果我修改示例,将lazy 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)
线程“main”java.lang.RuntimeException中的异常:没有会话绑定到当前线程,必须通过session.create创建会话
并通过“work”或“bindToCurrentThread”绑定到线程
在scala.Predef$.error处(Predef.scala:58)
在org.squeryl.Session$$anonfun$currentSession$1.apply上(Session.scala:111)
在org.squeryl.Session$$anonfun$currentSession$1.apply上(Session.scala:111)
位于scala.Option.getOrElse(Option.scala:104)
在org.squeryl.Session$.currentSession(Session.scala:110)上
在org.squeryl.dsl.AbstractQuery.org$squeryl$dsl$AbstractQuery$$\u dbAdapter(AbstractQuery.scala:116)
位于org.squeryl.dsl.AbstractQuery$$anon$1。(AbstractQuery.scala:120)
位于org.squeryl.dsl.AbstractQuery.iterator(AbstractQuery.scala:118)
位于org.squeryl.dsl.DelegateQuery.iterator(DelegateQuery.scala:9)
但是,正如我所说,如果我将调用方包装在一个事务中,那么一切都会正常工作
那么,我如何将这个对象由对象本身中的数据库支持这一事实封装起来呢?我假设您在调用courses对象时遇到了这个错误 我不太了解Squiryl是如何工作的,但我相信OneToMany[课程]是一个活生生的对象。这意味着对courses对象的调用需要一个会话,因为任何调用都可能延迟地转到数据库获取数据
如何组织这项工作取决于您使用的应用程序类型。在web应用程序中,添加过滤器(第一个入口点)来启动和停止事务通常是有意义的。在GUI客户端(比如swing应用程序)中,在接收到用户交互的地方启动事务是一个很好的解决方案。这样一来,您得到的事务不会太长,也会延伸到您希望以原子方式执行的调用上(完全执行或根本不执行)。Hmm,也许我的示例太简单了。实际上,我并不是在尝试来自squeryl文档的示例,但我的代码并不复杂(结构上的唯一区别是我的代码有更多的列)。我通过调用伴生对象中的函数来获取对象的实例,该函数确实使用事务,但从封装的角度来看,这似乎很好,因为伴生对象链接到DB支持的类。我的应用程序实际上没有任何用户交互(除了用户启动它)。它只是生成报告。由于您正在创建报告,我假设您没有进行任何写入。将整个操作打包到事务中不应有任何损害。