我一直在学习scala,playframework和光滑,但我发现了一个问题.我正在尝试创建一个简单的CRUD,一个列表控制器接收一个自定义过滤器字段,一些分页信息(页面大小和数量)和一个字符串元组的Seq与字段名称和顺序(asc或desc),以及一切工作正常,除了seq的订单,我不能通过动态订单.
我从Scadiddle博客得到了基本结构.所以,基本代码如下:
我有我的基本颜色模型:
case class Color(
id: Int,
name: String)
Run Code Online (Sandbox Code Playgroud)
这是一个简单的表定义:
class ColorsTable(tag: Tag) extends Table[Color](tag, "color") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def * = (id, name) <> ((Color.apply _).tupled, Color.unapply)
}
Run Code Online (Sandbox Code Playgroud)
在我的回购中,我有搜索方法:
def findAll(searchTerm: Option[String], page: Int, top: Int, sortsBy: Seq[(String, SortDirection)]): Future[Seq[Color]] = {
var query = searchTerm match {
case Some(term) => colors.filter(_.name like s"%$term%")
case _ => colors
}
val offset = (page - 1) * top
// This is building the sort clause, matching on each column in the sort
sortsBy.foreach {
sortTuple =>
val (sortColumn, sortDirection) = sortTuple
query = query.sortBy(sortColumn match {
case "id" => if (sortDirection == Desc) _.id.desc else _.id.asc
case _ => if (sortDirection == Desc) _.name.desc else _.name.asc
})
}
// The "list" method actually executes the query
val colorsQuery = query.drop(offset).take(top).result
db.run(colorsQuery)
}
Run Code Online (Sandbox Code Playgroud)
问题是,当我用这个序列调用搜索方法时:
val sortsBy = Seq[(String, SortDirection)](("name", Desc), ("id", Asc))
colorService.getColors(None, 1, 10, sortsBy).map(colorList => Ok(Json.toJson(colorList)))
Run Code Online (Sandbox Code Playgroud)
生成此查询:
select "id", "name" from "color" order by "id", "name" desc limit 10 offset 0
Run Code Online (Sandbox Code Playgroud)
如您所见,sortBy的顺序被反转(id然后是name,而不是name和id作为序列).
如果我使用元组而不是foreach,那么顺序就会受到尊重:
query = query.sortBy(
s => (s.name.desc, s.id.asc)
)
Run Code Online (Sandbox Code Playgroud)
但是没有办法生成动态大小的元组.为了增加一些困惑,另一件让我遇到麻烦的事情就是光滑文档中的这一部分:
请注意,具有多个列的单个ORDER BY不等同于多个.sortBy调用,而是等同于传递元组的单个.sortBy调用
那么,实际上我可以使用foreach并连接订单吗?或者是因为订单被逆转的这种限制?
如果只有元组可以用于sortBy,我怎样才能实现动态大小的顺序?
PD:感谢关注并对不好的英语感到抱歉
编辑:
感谢您的快速反应,我尝试了您的代码并且看起来很好,遗憾的是我几乎不知道它是如何工作的:((scala是一个非常好的,但很难学习的语言:S).
当我看到Higher Kinded Type Should be Enabled我吓坏了,寻找答案时,这并没有给我很大的希望,让我很容易理解,希望当我完成Scala编程,第3版,我会更加了解和了解到底是怎么回事.
还有一个问题,这相当于做几个sortBy调用吗?如何比较使用元组?我仍然对这部分光滑的文档感到困惑:
具有多个列的单个ORDER BY不等同于多个.sortBy调用,而是等同于传递元组的单个.sortBy调用
我检查了我的方法,并通过添加一个反向seq使它工作正常,当然不像你的代码那样功能和很好,所以我将使用你的建议,并努力使其余的过滤器与助手和避免瓦尔.(是的,在另一部分我仍然使用var,但是当我更多地了解Scala时,我会更好).
忏悔:经过8年多的语言编程(从JavaScript到Java,C#,Python等)我不得不重复一遍,Scala看起来像一个美丽但非常复杂的语言,但我不会放弃学习它
我们来定义DynamicSortBySupport帮助器
object DynamicSortBySupport {
import slick.ast.Ordering.Direction
import slick.ast.Ordering
import slick.lifted.Query
import slick.lifted.ColumnOrdered
import slick.lifted.Ordered
type ColumnOrdering = (String, Direction) //Just a type alias
trait ColumnSelector {
val select: Map[String, Rep[_]] //The runtime map between string names and table columns
}
implicit class MultiSortableQuery[A <: ColumnSelector, B, C[_]](query: Query[A, B, C]) {
def dynamicSortBy(sortBy: Seq[ColumnOrdering]): Query[A, B, C] =
sortBy.foldRight(query){ //Fold right is reversing order
case ((sortColumn, sortOrder), queryToSort) =>
val sortOrderRep: Rep[_] => Ordered = ColumnOrdered(_, Ordering(sortOrder))
val sortColumnRep: A => Rep[_] = _.select(sortColumn)
queryToSort.sortBy(sortColumnRep)(sortOrderRep)
}
}
}
Run Code Online (Sandbox Code Playgroud)
并重新定义您Table添加"排序图"
class ColorsTable(tag: Tag) extends Table[Color](tag, "color") with DynamicSortBySupport.ColumnSelector {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def * = (id, name) <> ((Color.apply _).tupled, Color.unapply)
val select = Map(
"id" -> (this.id),
"name" -> (this.name)
)
}
Run Code Online (Sandbox Code Playgroud)
最后在你的代码中使用整个东西:
object FindAll extends App {
import DynamicSortBySupport._
import slick.ast.Ordering.Direction
import slick.ast.Ordering
object colors extends TableQuery(new ColorsTable(_))
val sortsBy = Seq[(String, Direction)](("name", Ordering.Desc), ("id", Ordering.Asc)) //Replaced
val db = Database.forURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver="org.h2.Driver") //Just for testing
findAll(sortsBy)
def findAll(sortsBy: Seq[(String, Direction)]): Future[Seq[Color]] = {
val query = colors.dynamicSortBy(sortsBy).result
db.run(query)
}
}
Run Code Online (Sandbox Code Playgroud)
备注和评论:
Map[String, Rep[_]]字符串名称和表列之间的运行时映射可以通过错误处理来改进(现在它只抛出必须正确管理的运行时异常)或者从表定义本身自动派生;SortDirection用适当的替换slick.ast.Ordering.Direction,随意写一个转换器;filterOption;foldRight反向排序顺序;var并且功能正常:-)ColumnSelector数据层之外(实际上这是一个很好的做法)你可以重写它需要隐含的东西ColumnSelector[T];| 归档时间: |
|
| 查看次数: |
2321 次 |
| 最近记录: |