4

我开始使用在后端使用 Hibernate (JPA) 的 Scala 应用程序。为了加载一个对象,我使用这行代码:

val addr = s.load(classOf[Address], addr_id).asInstanceOf[Address];

不用说,这有点痛苦。我写了一个看起来像这样的辅助类:

import org.hibernate.Session

class DataLoader(s: Session) {
  def loadAddress(id: Long): Address = {
    return s.load(classOf[Address], id).asInstanceOf[Address];
  }
  ...
}

所以,现在我可以这样做:

val dl = new DataLoader(s)
val addr = dl loadAddress(addr_id)

问题是:如何编写一个通用的参数化方法,它可以使用相同的模式加载任何对象?IE

val addr = dl load[Address](addr_id)

(或类似的规定。)

我是 Scala 的新手,所以请原谅这里特别可怕的任何事情。

4

2 回答 2

5

这里是:

import org.hibernate.Session
class DataLoader(s: Session) {
  def load[A](id: Long)(implicit m: Manifest[A]): A = {
    return s.load(m.erasure, id).asInstanceOf[A];
  }
}

编辑——或者,为了确保任何转换错误——由于休眠返回错误的对象——将发生在内部load,如下所示:

import org.hibernate.Session
class DataLoader(s: Session) {
  def load[A](id: Long)(implicit m: Manifest[A]): A = {
    return m.erasure.asInstanceOf[Class[A]].cast(s.load(m.erasure, id));
  }
}

在 Scala 2.8 上,你也可以这样写:

import org.hibernate.Session
class DataLoader(s: Session) {
  def load[A : Manifest](id: Long): A = {
    return s.load(manifest[A].erasure, id).asInstanceOf[A];
  }
}

正如Chris所建议的,您也可以将其与隐式会话结合使用:

def load[A](id: Long)(implicit m: Manifest[A], s: org.hibernate.Session): A = {
  return s.load(m.erasure, id).asInstanceOf[A];
}

请注意,您不能将上下文视图符号 ( A : Manifest) 与其他隐式参数结合使用。

于 2010-03-12T17:56:40.437 回答
3

一种方法是利用该java.lang.Class.cast方法来执行以下操作:

def load[A](clazz: Class[A], id: Long)(implicit s: Session) : A 
       = clazz.cast(s.load(clazz, id))

那么用法如下:

implicit val s = ...//get hibernate session
val addr = load(classOf[Address], 1)

它与您已经拥有的并没有太大的不同,但是为了访问class实例,您需要将其传入。

我非常有信心你不能安全地做你想做的事,Manifests因为他们不能Class[Address]在编译时提供你需要的参数化,以便演员工作(他们只能提供擦除Class[_]。我没有看到任何其他机制可以从Manifest

您当然可以使用asInstanceOf[A]代替,cast但这会在编译时被删除,isInstanceOf[Object]因此在编译时类型检查方面是无用的(因此不建议使用)。

于 2010-03-12T15:12:26.077 回答