查询(三)
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
这种方法支持查询,更新和删除数据。