作为一个不熟悉Python的人,我经常听到很多赞美SQLAlchemy。所以我想明白:
Java(或Scala)世界中是否有更接近的等价物?我已经看到Apache Empire-DB在这方面提到了......
答案 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功能列表,它无法分享的一些功能:
当然,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 Vogt在SLICK上的Scala Days Skills Matters,ScalaQuery的下一个演变
答案 3 :(得分:6)
您还可以使用最近添加到类型安全堆栈的Slick。
答案 4 :(得分:1)
这是“Active Record”设计模式的Java实现。它的灵感来自Ruby on Rails的ActiveRecord ORM。它可能符合您的需求。
https://code.google.com/p/activejdbc/
或
Java的SQL便捷库。它尝试使用集合,bean等在idiommatic Java中公开关系数据库访问,同时保持与JDBC相同的细节级别。