哪些 ORM 与 Scala 配合得很好?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1140448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:32:05  来源:igfitidea点击:

What ORMs work well with Scala?

databaseormscala

提问by Clinton N. Dreisbach

I'm about to write a Scala command-line application that relies on a MySQL database. I've been looking around for ORMs, and am having trouble finding one that will work well.

我即将编写一个依赖于 MySQL 数据库的 Scala 命令行应用程序。我一直在寻找 ORM,但很难找到一种可以正常工作的 ORM。

The Lift ORMlooks nice, but I'm not sure it can be decoupled from the entire Lift web framework. ActiveObjects also looks OK, but the author says that it may not work well with Scala.

电梯ORM看起来不错,但我不知道它可以从整个电梯的Web框架分离。ActiveObjects 看起来也不错,但作者说它可能不适用于 Scala。

I'm not coming to Scala from Java, so I don't know all the options. Has anyone used an ORM with Scala, and if so, what did you use and how well did it work?

我不是从 Java 来到 Scala 的,所以我不知道所有的选择。有没有人在 Scala 中使用过 ORM,如果是,您使用的是什么以及它的效果如何?

采纳答案by incarnate

There are several reasons why JPA-oriented frameworks (Hibernate, for instance) do not fit into idiomatic Scala applications elegantly:

面向 JPA 的框架(例如 Hibernate)不能优雅地融入惯用的 Scala 应用程序有几个原因:

  • there are no nested annotations as states the Scala 2.8 Preview-- that means you cannot use annotations as mapping metadata for complex applications (even the simplest ones often use @JoinTable-> @JoinColumn);
  • inconsistencies between Scala and Java collections make developers convert collections; there are also cases when it is impossible to map Scala collections to associations without implementing complex interfaces of the underlying framework (Hibernate's PersistentCollections, for example);
  • some very common features, such as domain model validation, require JavaBeans conventions on persistent classes -- these stuff is not quite "Scala way" of doing things;
  • of course, the interop problems (like Raw Types or proxies) introduce a whole new level of issues that cannot be walked around easily.
  • Scala 2.8 预览版中没有嵌套注释——这意味着您不能将注释用作复杂应用程序的映射元数据(即使是最简单的应用程序也经常使用@JoinTable-> @JoinColumn);
  • Scala 和 Java 集合之间的不一致导致开发者转换集合;在某些情况下,如果不实现底层框架的复杂接口(PersistentCollections例如Hibernate 的 ),就不可能将 Scala 集合映射到关联;
  • 一些非常常见的特性,比如域模型验证,需要 JavaBeans 对持久类的约定——这些东西不是完全“Scala 方式”的做事;
  • 当然,互操作问题(如原始类型或代理)引入了无法轻易解决的全新级别的问题。

There are more reasons, I'm sure. That's why we have started the Circumflex ORM project. This pure-Scala ORM tries it's best to eliminate the nightmares of classic Java ORMs. Specifically, you define your entities in pretty much way you would do this with classic DDL statements:

还有更多的原因,我敢肯定。这就是我们启动Circumflex ORM 项目的原因。这个纯 Scala ORM 试图最好地消除经典 Java ORM 的噩梦。具体来说,您定义实体的方式与使用经典 DDL 语句的方式非常相似:

class User extends Record[User] {
  val name = "name".TEXT.NOT_NULL
  val admin = "admin".BOOLEAN.NOT_NULL.DEFAULT('false')
}

object User extends Table[User] {
  def byName(n: String): Seq[User] = criteria.add(this.name LIKE n).list
}

// example with foreign keys:
class Account extends Record[Account] {
  val accountNumber = "acc_number".BIGINT.NOT_NULL
  val user = "user_id".REFERENCES(User).ON_DELETE(CASCADE)
  val amount = "amount".NUMERIC(10,2).NOT_NULL
}

object Account extends Table[Account]

As you can see, these declarations are a bit more verbose, than classic JPA POJOs. But in fact there are several concepts that are assembled together:

如您所见,这些声明比经典的 JPA POJO 更加冗长。但实际上有几个概念组装在一起:

  • the precise DDL for generating schema (you can easily add indexes, foreign keys and other stuff in the same DSL-like fashion);
  • all queries can be assembled inside that "table object" instead of being scattered around in DAO; the queries themselves are veryflexible, you can store query objects, predicates, projections, subqueries and relation aliases in variables so you can reuse them, and even make batch update operations from existing queries (insert-select for example);
  • transparent navigation between associations (one-to-one, many-to-one, one-to-many and many-to-many-through-intermediate-relation) can be achieved either by lazy or by eager fetching strategies; in both cases the associations are established on top of the foreign keys of underlying relations;
  • validation is the part of framework;
  • there is also a Maven2 plugin that allows generating schema and importing initial data from handy XML formatted files.
  • 用于生成模式的精确 DDL(您可以轻松地以类似 DSL 的方式添加索引、外键和其他内容);
  • 所有查询都可以在“表对象”中组装,而不是分散在 DAO 中;查询本身非常灵活,您可以将查询对象、谓词、投影、子查询和关系别名存储在变量中,以便您可以重用它们,甚至可以对现有查询进行批量更新操作(例如插入选择);
  • 关联之间的透明导航(一对一、多对一、一对多和多对多通过中间关系)可以通过懒惰或急切的获取策略来实现;在这两种情况下,关联都建立在基础关系的外键之上;
  • 验证是框架的一部分;
  • 还有一个 Maven2 插件,允许从方便的 XML 格式文件生成模式和导入初始数据。

The only things Circumflex ORM lacks are:

Circumflex ORM 唯一缺乏的是:

  • multi-column primary keys (although it is possible to create multi-column foreign keys backed by multi-column unique constraints, but it is only for data integrity);
  • full-fledged documentation (although we are actively working on it);
  • success stories of ten-billion-dollar production systems that have Circumflex ORM as it's core technology.
  • 多列主键(虽然可以创建由多列唯一约束支持的多列外键,但这只是为了数据完整性);
  • 完整的文档(尽管我们正在积极致力于此);
  • 以 Circumflex ORM 为核心技术的 100 亿美元生产系统的成功案例。

P.S. I hope this post will not be considered an advertisement. It isn't so, really -- I was trying to be as objective as possible.

PS我希望这篇文章不会被视为广告。事实并非如此 - 我试图尽可能客观。

回答by dkaylor

I experimented with EclipseLink JPAand basic operations worked fine for me. JPA is a Java standard and there are other implementations that may also work (OpenJPA, etc). Here is an example of what a JPA class in Scala looks like:

我尝试了EclipseLink JPA,基本操作对我来说效果很好。JPA 是一个 Java 标准,还有其他的实现也可以工作(OpenJPA等)。以下是 Scala 中 JPA 类的示例:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity { val name = "Users" }
class User {
  @Id
  @GeneratedValue
  var userid:Long = _

  var login:String = _

  var password:String = _

  var firstName:String = _

  var lastName:String = _
}

回答by Konstantinos Kougios

I am happy to announce the 1st release of a new ORM library for Scala. MapperDao maps domain classes to database tables. It currently supports mysql, postgresql (oracle driver to be available soon), one-to-one, many-to-one, one-to-many, many-to-many relationships, autogenerated keys, transactions and optionally integrates nicely with spring framework. It allows freedom on the design of the domain classes which are not affected by persistence details, encourages immutability and is type safe. The library is not based on reflection but rather on good Scala design principles and contains a DSL to query data, which closely resembles select queries. It doesn't require implementation of equals() or hashCode() methods which can be problematic for persisted entities. Mapping is done using type safe Scala code.

我很高兴地宣布 Scala 的新 ORM 库的第一个版本。MapperDao 将域类映射到数据库表。它目前支持 mysql、postgresql(即将推出 oracle 驱动程序)、一对一、多对一、一对多、多对多关系、自动生成的密钥、事务,并可选择与 spring 很好地集成框架。它允许不受持久性细节影响的领域类的设计自由,鼓励不变性并且是类型安全的。该库不是基于反射,而是基于良好的 Scala 设计原则,并包含用于查询数据的 DSL,它与选择查询非常相似。它不需要实现 equals() 或 hashCode() 方法,这对于持久化实体来说可能是有问题的。映射是使用类型安全的 Scala 代码完成的。

Details and usage instructions can be found at the mapperdao's site:

详细信息和使用说明可以在 mapperdao 的网站上找到:

http://code.google.com/p/mapperdao/

http://code.google.com/p/mapperdao/

The library is available for download on the above site and also as a maven dependency (documentation contains details on how to use it via maven)

该库可在上述站点上下载,也可作为 maven 依赖项下载(文档包含有关如何通过 maven 使用它的详细信息)

Examples can be found at:

可以在以下位置找到示例:

https://code.google.com/p/mapperdao-examples/

https://code.google.com/p/mapperdao-examples/

Very brief introduction of the library via code sample:

通过代码示例非常简要地介绍该库:

class Product(val name: String, val attributes: Set[Attribute])
class Attribute(val name: String, val value: String)
...

val product = new Product("blue jean", Set(new Attribute("colour", "blue"), new Attribute("size", "medium")))
val inserted = mapperDao.insert(ProductEntity, product)
// the persisted entity has an id property:
println("%d : %s".format(inserted.id,inserted))

Querying is very familiar:

查询很熟悉:

val o=OrderEntity

import Query._
val orders = query(select from o where o.totalAmount >= 20.0 and o.totalAmount <= 30.0)
println(orders) // a list of orders

I encourage everybody to use the library and give feedback. The documentation is currently quite extensive, with setup and usage instructions. Please feel free to comment and get in touch with me at kostas dot kougios at googlemail dot com.

我鼓励大家使用图书馆并提供反馈。该文档目前相当广泛,包括设置和使用说明。请随时发表评论并通过 googlemail dot com 的 kostas dot kougios 与我联系。

Thanks,

谢谢,

Kostantinos Kougios

科斯坦蒂诺斯·库吉奥斯

回答by Hyman

Slickis a perfect match for a functional world. Traditional ORM's are not a perfect fit for Scala. Slick composes well and uses a DSL that mimics Scala collection classes and for comprehensions.

Slick是功能世界的完美搭档。传统的 ORM 并不适合 Scala。Slick 组合得很好,并使用了一种 DSL 来模拟 Scala 集合类和用于推导。

回答by Ikai Lan

Here's basically the same example with @Column annotation:

这是带有@Column 注释的基本相同的示例:

 /*
   Corresponding table:

 CREATE TABLE `users` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `admin` tinyint(1) default '0',
  PRIMARY KEY  (`id`)
) 

*/

import _root_.javax.persistence._

@Entity
@Table{val name="users"}
class User {

  @Id
  @Column{val name="id"}
  var id: Long = _

  @Column{val name="name"}
  var name: String = _

  @Column{val name="admin"}
  var isAdmin: Boolean = _

  override def toString = "UserId: " + id + " isAdmin: " + isAdmin + " Name: " + name

}

回答by Lukas Eder

Of course, any Java database access framework will work in Scala as well, with the usual issues that you may encounter, such as collections conversion, etc. jOOQ for instance, has been observed to work well in Scala. An example of jOOQ code in Scala is given in the manual:

当然,任何 Java 数据库访问框架也可以在 Scala 中运行,但您可能会遇到一些常见的问题,例如集合转换等。例如,jOOQ 已被观察到在 Scala 中运行良好。手册中给出了 Scala 中的 jOOQ 代码示例:

object Test {
  def main(args: Array[String]): Unit = {
    val c = DriverManager.getConnection("jdbc:h2:~/test", "sa", "");
    val f = new Factory(c, SQLDialect.H2);
    val x = T_AUTHOR as "x"

    for (r <- f
        select (
          T_BOOK.ID * T_BOOK.AUTHOR_ID,
          T_BOOK.ID + T_BOOK.AUTHOR_ID * 3 + 4,
          T_BOOK.TITLE || " abc" || " xy"   
        )
        from T_BOOK
        leftOuterJoin (
          f select (x.ID, x.YEAR_OF_BIRTH)
          from x
          limit 1
          asTable x.getName()
        )
        on T_BOOK.AUTHOR_ID === x.ID
        where (T_BOOK.ID <> 2)
        or (T_BOOK.TITLE in ("O Alquimista", "Brida"))
        fetch
    ) {
      println(r)
    }
  }
}

Taken from http://www.jooq.org/doc/2.6/manual/getting-started/jooq-and-scala/

取自 http://www.jooq.org/doc/2.6/manual/getting-started/jooq-and-scala/