Подтвердить что ты не робот

Какие ORM работают с Scala?

Я собираюсь написать приложение командной строки Scala, основанное на базе данных MySQL. Я искал ORM, и мне трудно найти тот, который будет работать хорошо.

Lift ORM выглядит неплохо, но я не уверен, что он может быть отделен от всего веб-фрейма Lift. ActiveObjects также выглядит нормально, но автор говорит, что он может плохо работать с Scala.

Я не прихожу к Scala с Java, поэтому я не знаю всех параметров. Кто-нибудь использовал ORM с Scala, и если да, то что вы использовали и насколько хорошо он работал?

4b9b3361

Ответ 1

Существует несколько причин, по которым JPA-ориентированные фреймворки (например, Hibernate) не вписываются в идиоматические приложения Scala:

  • нет вложенных аннотаций в качестве состояний Scala 2.8 Preview - это означает, что вы не можете использовать аннотации как метаданные отображения для сложных приложений ( даже самые простые часто используют @JoinTable@JoinColumn);
  • несоответствия между Scala и коллекциями Java заставляют разработчиков конвертировать коллекции; есть также случаи, когда невозможно сопоставить коллекции Scala с ассоциациями без реализации сложных интерфейсов базовой структуры (например, Hibernate PersistentCollections);
  • некоторые очень распространенные функции, такие как проверка модели домена, требуют соглашений JavaBeans в постоянных классах - это не совсем "способ w64" для выполнения вещей;
  • конечно, проблемы взаимодействия (например, Raw Types или proxies) вводят совершенно новый уровень проблем, которые легко можно обойти.

У меня больше причин, я уверен. Вот почему мы начали проект 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]

Как вы можете видеть, эти объявления являются немного более подробными, чем классические POJO JPA. Но на самом деле существует несколько концепций, которые собраны вместе:

  • точный DDL для генерации схемы (вы можете легко добавлять индексы, внешние ключи и другие вещи тем же способом DSL);
  • все запросы могут быть собраны внутри этого "табличного объекта", а не разбросаны в DAO; сами запросы очень гибкие, вы можете хранить объекты запроса, предикаты, проекции, подзапросы и псевдонимы отношений в переменных, чтобы их можно было повторно использовать, и даже выполнять операции пакетного обновления из существующих запросов (например, вставить-select);
  • прозрачная навигация между ассоциациями (взаимно-однозначное, много-к-одному, одно-ко-многим и много-много-через-промежуточное отношение) может быть достигнута либо ленивыми, либо энергичными стратегиями отбора; в обоих случаях ассоциации устанавливаются поверх внешних ключей базовых отношений;
  • валидация - это часть структуры;
  • существует также плагин Maven2, который позволяет генерировать схему и импортировать исходные данные из удобных файлов в формате XML.

Единственные недостатки Circumflex ORM:

  • первичные ключи с несколькими столбцами (хотя возможно создание многоколоночных внешних ключей, поддерживаемых уникальными ограничениями с несколькими столбцами, но это только для целостности данных);
  • полноценная документация (хотя мы активно работаем над ней);
  • истории успеха десятимиллиардных производственных систем, в которых Circumflex ORM является основной технологией.

P.S. Надеюсь, этот пост не будет считаться рекламой. Это не так, на самом деле - я старался быть максимально объективным.

Ответ 2

Я экспериментировал с EclipseLink JPA, и основные операции работали отлично для меня. JPA - это стандарт Java, и есть и другие реализации, которые могут также работать (OpenJPA и т.д.). Вот пример того, как выглядит класс JPA в Scala:

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 = _
}

Ответ 3

Я рад объявить 1-й выпуск новой библиотеки ORM для Scala. MapperDao сопоставляет классы домена с таблицами базы данных. В настоящее время он поддерживает mysql, postgresql (драйвер oracle скоро будет доступен), отношения "один к одному", "один к одному", "один ко многим", "многие ко многим", автоматически генерируемые ключи, транзакции и, возможно, w760 > . Это позволяет свободно разрабатывать классы домена, на которые не влияют детали сохранения, поощряет неизменность и безопасен по типу. Библиотека основана не на размышлениях, а на хороших принципах дизайна Scala и содержит DSL для запроса данных, которые очень похожи на выбранные запросы. Это не требует реализации методов equals() или hashCode(), которые могут быть проблематичными для сохраняемых объектов. Картирование выполняется с использованием безопасного типа Scala.

Подробности и инструкции по использованию можно найти на сайте mapperdao:

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

Библиотека доступна для загрузки на вышеуказанном сайте, а также в качестве зависимости от maven (документация содержит подробную информацию о том, как ее использовать через maven)

Примеры можно найти по адресу:

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

Очень короткое введение библиотеки через образец кода:

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))

Запрос очень знаком:

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

Я призываю всех использовать библиотеку и давать отзывы. Документация в настоящее время довольно обширна, с инструкциями по настройке и использованию. Пожалуйста, не стесняйтесь комментировать и связываться со мной в kostas dot kougios в googlemail dot com.

Спасибо,

Костантинос Кужиос

Ответ 4

Здесь в основном тот же пример с аннотацией @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

}

Ответ 5

Slick - идеальное сочетание для функционального мира. Традиционные ORM не подходят для Scala. Слик хорошо складывается и использует DSL, который имитирует классы коллекции Scala и для понимания.

Ответ 6

Конечно, любая инфраструктура доступа к базе данных Java будет работать и в Scala, так как обычные проблемы, с которыми вы можете столкнуться, например преобразование коллекций и т.д., например, jOOQ хорошо работает в Scala, Пример кода jOOQ в Scala приведен в руководстве:

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)
    }
  }
}

Взято из http://www.jooq.org/doc/2.6/manual/getting-started/jooq-and-scala/