Slick 编程(8): 查询(三)

jerry Scala 2015年11月26日 收藏

Slick的查询实际上是执行由Invoker(无参数时为UnitInvoker)Trait定义的方法, Slick定义了一个从Query隐含的变换,使得你可以直接执行查询操作,最常用的一个情况是把整个查询结果存放到一个Scala集合类型中(比如使用list方法)

val l = q.list
val v = q.buildColl[Vector]
val invoker = q.invoker
val statement = q.selectStatement

所有的查询方法都定义了一个隐含参数Session,如果你愿意,你也可以直接传入一个session参数:

val l = q.list()(session)

如果你只需要单个查询结果,你可以使用first或firstOption方法,而方法foreach, foldLeft,和elements方法可以用来遍历查询结果而不需要先把结果复制到另外一个Scala集合对象中。

Deleting
删除数据和查询很类似,你首先写一个选择查询,然后调用它的delete方法,同样Slick也定义一个从Query到DeleteInvoker的隐含转换,DeleteInvoker定义了delete方法

val affectedRowsCount = q.delete
val invoker = q.deleteInvoker
val statement = q.deleteStatement

定义用来删除记录的查询时只能使用单个表格。

Inserting
插入操作基于单个表定义的字段映射,当你直接使用某个表来插入数据时,这个操作基于表类型中定义的“*?,如果你省略某些字段,那么插入这些省略的字段会使用缺省值,所有的插入操作方法定义在InsertInvoker和FullInsertInvoker。

coffees += ("Colombian", 101, 7.99, 0, 0)

coffees ++= Seq(
  ("French_Roast", 49, 8.99, 0, 0),
  ("Espresso",    150, 9.99, 0, 0)
)

// "sales" and "total" will use the default value 0:
coffees.map(c => (c.name, c.supID, c.price)) += ("Colombian_Decaf", 101, 8.99)

val statement = coffees.insertStatement
val invoker = coffees.insertInvoker

// compiles to SQL:
//   INSERT INTO "COFFEES" ("COF_NAME","SUP_ID","PRICE","SALES","TOTAL") VALUES (?,?,?,?,?)

如果你的插入操作定义了自动增一的字段,该字段会自动忽略,由数据库本身来插入该字段的值。缺省情况+=返回受影响的行数(通常总为1),而++操作给出总计的行数(以Option类型给出),你可以使用returning修改返回的值,比如返回插入的行的主键:

val userId =
  (users returning users.map(_.id)) += User(None, "Stefan", "Zeiger")

要注意的是很多数据库只支持返回自动增一的作为主键的那个字段,如果想返回其它字段,可能会抛出SlickException 异常。

除了上面的插入记录的方法,还可以使用服务器端表达式的方发插入数据:

class Users2(tag: Tag) extends Table[(Int, String)](tag, "users2") {
  def id = column[Int]("id", O.PrimaryKey)
  def name = column[String]("name")
  def * = (id, name)
}
val users2 = TableQuery[Users2]

users2.ddl.create

users2 insert (users.map { u => (u.id, u.first ++ " " ++ u.last) })

users2 insertExpr (users.length + 1, "admin")

Updating
更新记录也是先写查询,然后调用update方法,比如:

val q = for { c <- coffees if c.name === "Espresso" } yield c.price
q.update(10.49)

val statement = q.updateStatement
val invoker = q.updateInvoker

update方法定义在UpdateInvoker Trait中。

Compiled Queries
数据库查询时,通常需要定义一些查询参数,比如根据ID查找对应的记录。你可以定义一个带参数的函数来定义查询对象,但每次调用该函数时都要重新编译这个查询语句,系统消耗有些大,Slick支持预编译这个带参数的查询函数,例如:

def userNameByIDRange(min: Column[Int], max: Column[Int]) =
  for {
    u <- users if u.id >= min && u.id < max
  } yield u.first

val userNameByIDRangeCompiled = Compiled(userNameByIDRange _)

// The query will be compiled only once:
val names1 = userNameByIDRangeCompiled(2, 5).run
val names2 = userNameByIDRangeCompiled(1, 3).run

这种方法支持查询,更新和删除数据。