一直想给ScalaFX找一个合适的持久曾框架,要越方便越好。
接触Scala之前玩的是JavaFX,曾用熟悉的Mybatis写持久层,JavaFxBean的Properties不能用IDE自动生成用于Mybatis的getter和setter。比方说一个属性
private fianl IntegerProperty age = new SimpleIntegerProperty(this, "age", 20);用Eclipse或IDEA可以生成如下getter和setter
public IntegerProperty getAge() { return age; } public void setAge(IntegerProperty age) { this.age = age; }然而持久层框架需要的(也就是JavaFxBean的标配)是这样的getter和setter
public String getName() { return name.get(); } public void setName(String name) { this.name.set(name); } public StringProperty nameProperty() { return name; }自己写过一个简单的工具用来生产这样的getter和setter,但仍嫌麻烦。
(IDEA12.1已经支持生成JavaFX风格的getter和setter了)
(技术选型中,不喜请略过)
如今转向ScalaFX,Scala自带的BeanProperty注解生产的getter和setter也是JavaBean风格的,而IDEA12.1提供的便利也指望不上。所以一直在找替代方案。期间看到了OrientDB,这是一个纯Java的嵌入式NoSQL数据库,我是很看好它的,它甚至还提供了一个直接将JavaBean映射为Document的object模块。然而最大的问题是,object模块是直接映射Field,而不是getter和setter(源码中似乎是支持getter和setter的,因为是春节期间看的源码,再加上用的破笔记本,看不太仔细),同时对final字段会排出在外(而用val声明的字段恰好是final的)。本来想要改造orientdb-object模块,但并没有特别好的解决方案。
前些天学Play2的过程中Slick进入了我的视线,真正做到了零配置,也不需要写SQL。
(说实在的,为了做一个简单的查询,又要写建表语句,又要写各种SQL文,然后创建各种JavaBean,还有就是一堆配置文件,啊,简直要疯了。最好能省则省啊。)
本来JPA是个好选择,但是看网上JPA教材的时候第一眼看到了配置文件,我对配置文件那个烦啊(主要是记性不好,没IDE提示完全不知道怎么写),然后就不管它了。Slick好,没有配置文件,不需要写SQL(但需要定义Schema),那么就它吧。
(选型完毕,继续)
首先要声明一个ScalaFxBean,简单起见,只定义两个属性
class Person(_name: String, _age: Int) { def this() = this(null, 0) lazy val name = new StringProperty(this, "name", _name) lazy val age = new IntegerProperty(this, "age", _age) def name_=(v: String) { name() = v } def age_=(v: Int) { age() = v } override def toString = s"name = ${name()}; age = ${age()}" }这种类声明方式是参照ProJavaFX2中Scala and JavaFX一节。
Slick提供三种方式访问数据库(具体请在Slick官网了解),这里用的是叫做Lifted的方式,它实际上是将数据看作Tuple,我们需要将Tuple映射成对象(通过apply和unapply方法)
def apply(name: String, age: Int) = new Person(name, age) def unapply(p: Person) = Option((p.name(), p.age()))然后是定义Schema,我把apply和unapply也整合进来
object Persons extends Table[Person]("persons") { def name = column[String]("name", O.NotNull) def age = column[Int]("age") def * = name ~ age <>(Persons.apply _, Persons.unapply _) def apply(name: String, age: Int) = new Person(name, age) def unapply(p: Person) = Option((p.name(), p.age())) }然后就可以操作数据了
object UsePerson extends App { val p = new Person("misty", 23) val db = Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") val ddl = Persons.ddl db withSession { ddl.create Persons.insert(p) val q = Query(Persons) q foreach println ddl.drop } }也算是比较简洁了,但还有个缺点,就是ScalaBean和Schema之间有重复声明的感觉。
其实JPA可以算是将Schema以注解的方式合并到JavaBean中。明天再试试JPA(如果有精力的话),可惜没有Scala的JPA解决方案。