Какие ORM работают с Scala?
Я собираюсь написать приложение командной строки Scala, основанное на базе данных MySQL. Я искал ORM, и мне трудно найти тот, который будет работать хорошо.
Lift ORM выглядит неплохо, но я не уверен, что он может быть отделен от всего веб-фрейма Lift. ActiveObjects также выглядит нормально, но автор говорит, что он может плохо работать с Scala.
Я не прихожу к Scala с Java, поэтому я не знаю всех параметров. Кто-нибудь использовал ORM с Scala, и если да, то что вы использовали и насколько хорошо он работал?
Ответы
Ответ 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/