与SQLAlchemy for Java/Scala最接近的等价物
作为一个不熟悉Python的人,我经常听到很多对SQLAlchemy的赞扬。所以我想了解:与SQLAlchemy for Java/Scala最接近的等价物,java,scala,orm,sqlalchemy,relational-database,Java,Scala,Orm,Sqlalchemy,Relational Database,作为一个不熟悉Python的人,我经常听到很多对SQLAlchemy的赞扬。所以我想了解: 与“类型安全的SQL构建器”相比,它提供了什么 在Java(或Scala)世界中是否有更接近它的等价物?我看到在这方面提到过 提供类似于他们在图书馆主页上的“SQLALCHEMY的哲学”中所讨论的可组合性。您可以查询一个查询 val query = from(table)(t => where(t.a === 1) select(t)) val composed = from(query)(q =&
val query = from(table)(t => where(t.a === 1) select(t))
val composed = from(query)(q => where(q.b === 2) select(q))
它还分享了设计理念的一个很好的部分,主要是当事情变得复杂时,库应该“让开”,让开发人员自己调整事情。当SuleLi做对象映射时,我认为它比一个ORM更多的是DSL。
通过快速浏览SQLAlchemy功能列表,可以看到一些它没有共享的功能:
当然,Squeryl还提供了我认为Python库不能的一个主要特性,即编译器检查类型的查询安全性。
(参见下面关于“SLIK”的注释)可以做的简单:
for{
a <- Article
if a.dateCreated between(start, end)
_ <- Query groupBy a.reporterID orderBy a.dateCreated.desc
} yield(a)
用于{
SQLAlchemy值得注意的一点是,它使表成为第一类对象。因此,核心API实际上是围绕表对象编写的,因此API本质上是关系型的。因此,在这个级别上,即使API是OO,它也基本上反映了RDBMS对象或函数,如表、列、关系等OIN、别名等。在这个级别上,SQLAlchemy本质上为您提供了一个OOSQL,其中SQL和关系数据库没有被给予第二类处理。同样,在这个级别上,SQLAlchemy真正的光芒四射,因为这个抽象级别使您能够降低到“原始”级别关系级别,从而获得了我从未见过的任何其他ORM提供的巨大灵活性。有趣的是,在ORM中建模类继承所需的一些底层功能是在这一层实现的,例如联接表继承
更经常使用的API(至少最近)是声明式API,它实际上是更多的OO,将业务领域中的对象映射到我上面提到的对象(在大多数情况下是透明的)。这就是ORM功能的用武之地,该API与其他ORM API更为相似,在其他ORM API中,用户使用域对象,这些操作直接转换为底层表操作
据我所知,Scala中的ORM仍然在追赶Java中容易获得的功能(例如继承),尽管它们提供了其他功能(例如类型安全性、类似LINQ的构造),尽管它们面临一些严重问题,如22列限制。(我读过一些评论,其中很少有人想知道为什么任何人都需要超过22个专栏,至少在我的经验中,有些情况我不会称之为罕见,在这种情况下,一个人需要超过22个专栏的倍数)
scala中的ORM(尽管它们有着与Java不同的风格)我认为仍然能够满足需要。关于SQLAlchemy,我在Java或scala中见过与之相当的ORM吗?我没有见过
编辑:我忘了补充一点,就是即使使用声明式API,SQLAlchemy仍然可以直接访问底层对象以声明方式映射,Foo.\uuuu table\uuuuu是一个表对象,如果您愿意,可以直接使用。您也可以使用最近添加到typesafe堆栈中的对象。ActiveJDBC
它是“活动记录”设计模式的Java实现。它的灵感来自RubyonRails的活动记录ORM。它可能适合您的需要
或
JDBI
一个用于Java的SQL便利库。它试图在惯用Java中公开关系数据库访问,使用集合、bean等,同时保持与JDBC相同的细节级别
-该模式最初由Martin Fowler编写,以防您有兴趣进一步阅读。
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
}