Java/Scala中最接近SQLAlchemy的相当工具是什么?

31

作为一个不熟悉Python的人,我经常听到SQLAlchemy的好评。因此,我想了解:

  1. 与"类型安全的SQL构建器"(如jOOQQueryDSL)相比,它提供了什么?

  2. 在Java(或Scala)世界中,有更接近它的等价物吗?我曾看到Apache Empire-DB在这方面被提到...

5个回答

19
SQLAlchemy的一个显著特点是它将表格作为一等对象。因此,核心API实际上是围绕表格对象编写的,因此API本质上是关系型的。因此,在这个层面上,即使API是面向对象的,它本质上也反映了RDBMS对象或函数,例如表格、列、关系、连接、别名等。在这个层面上,SQLAlchemy为您提供了基本上是OOSQL的功能,其中SQL和关系型数据库没有被给予二等待遇。正是在这个层面上,SQLAlchemy真正闪耀,因为这种抽象级别使您能够下降到有点“原始”的关系级别,并因此获得巨大的灵活性,我真的没有看到任何其他ORM提供。有趣的是,ORM中建模类继承所需的一些基本功能在这一层中实现,例如联接表继承。http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html#joined-table-inheritance

最常用的API(至少最近)是声明式API,它实际上更加面向对象,并将业务域中的对象映射到上述对象中(在大多数情况下透明)。这就是ORM功能发挥作用的地方,API与其他ORM API有些类似,其中一个使用领域对象进行操作,这些操作直接转换为底层表操作。

据我所知,Scala中的ORM仍在努力追赶Java中容易获得的内容(例如继承),即使它们提供了其他功能(例如类型安全性、类似于LINQ的结构),即使它们在一些严重问题(例如22列限制)上存在问题。 (我读过一些评论,少数人想知道为什么有人需要超过22列,至少根据我的经验,有时需要多个列的情况并不罕见)。

我认为Scala中的ORM(即使它们呈现出不同的风格)仍在追赶所需内容。关于SQLAlchemy,在Java或Scala中是否有足够接近的等价物? 我没有看到过任何。

编辑:我忘记补充的一件事是,即使使用声明式API,SQLAlchemy仍然可以直接访问底层对象。因此,如果“class Foo”被映射为声明式,Foo.__table__就是表对象,如果需要,您可以直接使用它。


10

Squeryl 提供了类似于 "SQLALCHEMY'S PHILOSOPHY" 中所述的可组合性。您可以查询一个查询。

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.继承映射-这里有一些个人观点,但我认为当一个库这样做时,它经常违反“让开”的原则。
当然,Squeryl还提供了我认为Python库无法提供的重要功能,即编译器检查查询的类型安全性。

7

您还可以使用最近添加到typesafe堆栈中的Slick


7

ScalaQuery(请注意底部有关“slick”的注释)可以执行简单的操作:

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中生成强类型的复杂查询是不可能的,所以只能使用手写的SQL语句;直到我找到了ScalaQuery,这是一个启示,就像Scala语言本身一样。

无论如何,你有选择,Squeryl可能更符合SQL Alchemy,不确定,探索一下,你可能不会失望,在这里提供了很多Scala好东西,现在和未来都难免感到兴奋 ;-)

p.s. Zeiger和Vogt在Scala Days Skills Matters上的精彩演讲,介绍了SLICK,ScalaQuery的下一个进化版本


2

ActiveJDBC

这是一个Java实现的“Active Record”设计模式。它的灵感来自于Ruby on Rails中的ActiveRecord ORM。它可能适合你的需求。

https://javalite.io/activejdbc

或者

JDBI

这是一个Java的SQL便捷库。它试图使用集合、bean等符合Java语法的方式暴露关系数据库的访问,同时保持与JDBC相同的细节水平。

http://jdbi.org


这个模式最初是由Martin Fowler提出的,如果你有兴趣进一步了解它的话,可以阅读相关资料。 - Merlyn Morgan-Graham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接