最接近于SQLAlchemy for Java / Scala

时间:2012-05-10 15:52:39

标签: java scala orm sqlalchemy relational-database

作为一个不熟悉Python的人,我经常听到很多赞美SQLAlchemy。所以我想明白:

  1. jOOQQueryDSL等“类型安全的SQL构建器”相比,它提供了什么?

  2. Java(或Scala)世界中是否有更接近的等价物?我已经看到Apache Empire-DB在这方面提到了......

5 个答案:

答案 0 :(得分:16)

SQLAlchemy的一个值得注意的事情是它使表成为第一类对象。因此,核心API实际上是围绕表对象编写的,因此API本质上是关系性的。因此,在这个级别,即使API是OO,它本质上反映了RDBMS对象或函数,如表,列,关系,联接,别名等。在这个级别,SQLAlchemy为您提供了一个OOSQL,其中SQL和关系数据库没有给出二等治疗。此外,SQLAlchemy真的很闪耀,因为这种抽象级别使您能够降低到一点“原始”关系级别,从而获得巨大的灵活性,我真的没有看到任何其他ORM提供。有趣的是,在ORM中建模类继承所需的一些底层功能是在这一层实现的,例如。已加入表继承http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html#joined-table-inheritance

更经常使用的API(至少最近)是声明性API,它实际上是更多的OO,并将业务域中的对象映射到我上面提到的对象(在大多数情况下是透明的)。这是ORM功能的用武之地,API与其他ORM API有点类似,其中一个用于域对象,这些操作直接转换为基础表操作。

据我所知,Scala中的ORM仍在追赶Java中容易获得的东西(例如继承),即使它们提供其他功能(例如类型安全,类似LINQ的构造),即使是他们在解决一些严重的问题,如22列限制。 (我读过评论,其中很少有人想知道为什么有人需要超过22列,至少根据我的经验,有些情况我不会称之为罕见,需要多倍的情况。)

scala中的ORM(即使它们与Java具有不同的风格)我认为仍然可以追踪到所需的内容。关于SQLAlchemy,是否有足够接近我在Java或Scala中看到过的东西?我还没见过。

编辑:我忘记添加的一件事是,即使使用声明性API,SQLAlchemy仍然允许您直接访问底层对象。因此,如果“class Foo”以声明方式映射,则Foo .__ table__是您可以直接使用的表对象。

答案 1 :(得分:10)

Squeryl提供类似于他们在图书馆主页上的“SQLALCHEMY'S哲学”中所讨论的可组合性。您可以查询查询。

val query = from(table)(t => where(t.a === 1) select(t))
val composed = from(query)(q => where(q.b === 2) select(q))

它也分享了设计理念的很大一部分,主要是当事情变得复杂时,图书馆应该“摆脱困境”并允许开发人员自己调整事物。虽然Squeryl做对象映射,但我认为它更像是一个DSL而不是一个ORM。

通过快速浏览SQLAlchemy功能列表,它无法分享的一些功能:

  1. 能够使用原始SQL - 很难在标准ANSI SQL中找到任何无法表达的内容。
  2. 继承映射 - 这里有一些个人观点,但我认为当图书馆这样做时,它经常违反“走出去”的原则。
  3. 当然,Squeryl还提供了我认为Python库无法实现的主要功能,即编译器检查查询类型的安全性。

答案 2 :(得分:7)

ScalaQuery(请参阅底部有关“光滑”的说明)可以做到这一点:

for{
  a <- Article
  if a.dateCreated between(start, end)
  _ <- Query groupBy a.reporterID orderBy a.dateCreated.desc
} yield(a)

或任意复杂的通过组合:

val team = for{
  t <- Team
  s <- School if t.schoolID is s.id 
} yield (t,s)

val player = for{
  r <- Roster
  p <- Player if r.playerID is p.id
} yield (r, p)

val playerDetail = for{
  (r, p) <- player
} yield (p.id, p.firstName, p.lastName, r.jerseyID, r.position, r.gamesPlayed)

val scoring = for{
  (r, p) <- player
  s <- Scoring if p.id is s.playerID
  detail <- playerDetail 
} yield (r, p, s, detail)

val scoringDetail = for{
  (r, p, s, detail) <- scoring
  val (total, goals, assists) = 
    (s.playerID.count, s.goal.sum, (s.assist1.sum + s.assist2.sum))
  val ppg = (s.playerID.count / r.gamesPlayed)
} yield (goals, assists, total, ppg)

以下是如何获得团队统计数据(可以修改联盟或单人游戏视图):

val forScoring = for{
  start ~ end ~ teamID <- Parameters[JodaTime,JodaTime,Int]
  (r,p,s,player) <- scoring if r.teamID is teamID
  comp <- bindDate(start, end) if s.gameID is comp.id
  (goals, assists, total, ppg) <- scoringDetail
  _ <- Query groupBy p.id orderBy ( ppg.desc, total.asc, goals.desc )
} yield (player, goals, assists, total, ppg)

def getScoring(start: JodaTime, end: JodaTime, id: Int): List[TeamScoring] = {
  forScoring(start, end, id).list
}

我认为在Scala中生成强类型的复杂查询是不可能的,并且已经让我自己只是移植到了试用过的&amp;真正的手写SQL;也就是说,直到我遇到ScalaQuery,这是一个启示,就像Scala语言本身一样。

无论如何,你有选择,Squeryl可能更符合SQL Alchemy,不知道,探索一下,你可能不会感到失望,有很多Scala善良提供,很难不在这里,现在和之后感到头晕目眩; - )

P.S。 a great talk by Zeiger and VogtSLICK上的Scala Days Skills Matters,ScalaQuery的下一个演变

答案 3 :(得分:6)

您还可以使用最近添加到类型安全堆栈的Slick

答案 4 :(得分:1)

ActiveJDBC

这是“Active Record”设计模式的Java实现。它的灵感来自Ruby on Rails的ActiveRecord ORM。它可能符合您的需求。

https://code.google.com/p/activejdbc/

JDBI

Java的SQL便捷库。它尝试使用集合,bean等在idiommatic Java中公开关系数据库访问,同时保持与JDBC相同的细节级别。

http://jdbi.org