最接近于SQLAlchemy for Java/Scala

Ale*_*nov 27 java orm scala sqlalchemy relational-database

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

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

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

Dha*_*ene 17

关于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有点类似,其中一个用于域对象,这些操作直接转换为基础表操作.

尽我的意识,在斯卡拉奥姆斯还在追赶到什么是Java(如继承)容易获得,即使他们提供其他功能(如类型安全,LINQ样结构),即使他们奋斗与一些严重的问题,如22列限制.(我读过评论,其中很少有人想知道为什么有人需要超过22列,至少根据我的经验,有些情况我不会称之为稀有,其中需要的是其中的倍数).

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

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


Dav*_*ker 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))
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 能够使用原始SQL - 很难在标准ANSI SQL中找到任何无法表达的内容.
  2. 继承映射 - 这里有一些个人意见,但我认为当一个库这样做时,它经常违反"走出去"的原则.

当然,Squeryl还提供了我认为Python库无法实现的主要功能,即编译器检查查询类型的安全性.


vir*_*yes 7

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

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

或任意复杂的通过组成:

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)
Run Code Online (Sandbox Code Playgroud)

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

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

PS 大谈由Zeiger和沃格特在斯卡拉天技能事项SLICK,ScalaQuery的下一个演进


sim*_*mao 7

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