【发布时间】:2017-11-17 16:00:54
【问题描述】:
以下代码使用 scala anorm 打印所有行:
import anorm._
val query = s"select col_str, col_num from mytable"
val rowParser: RowParser[~[String, Int]] = SqlParser.str(1) ~ SqlParser.int(2)
def f(row: (String, Int)) {
println(row._1 + "\t" + row._2)
}
val rows: List[(String, Int)] = SQL(query).as(rowParser.*).map(SqlParser.flatten)
rows.foreach(f)
但是它需要将所有数据加载到内存中。避免加载所有数据的解决方案是使用fold,如下:
SQL(query).fold(Unit, ColumnAliaser.empty) { (_, r: Row) =>
println(r[String](1) + "\t" + r[Int](2))
Unit
}
但是,这里我没有使用rowParser 和flatten。如何修改前面的代码以使用rowParser 和flatten,而不将所有内容加载到内存中?像这样的东西(注意:这段代码不起作用):
SQL(query).as(rowParser.*).map(SqlParser.flatten).fold(Unit, ColumnAliaser.empty) { (_, row: (String, Int)) =>
f(row)
Unit
}
而且更困难的是,必须创建一个隐式的forEach2 函数,以便我可以按如下方式运行它:
SQL(query).as(rowParser.*).map(SqlParser.flatten).forEach2(f)
旧
我之前尝试过的一些代码:
def foreach[T, A, B](sqlQuery: SqlQuery, rowParser: RowParser[~[A, B]], f: (~[A, B]) => T) {
val result: Either[List[Throwable], Unit.type] = sqlQuery.fold(Unit, ColumnAliaser.empty) { (_, row: Row) =>
rowParser(row) match {
case Success(r: ~[A, B]) =>
f(r)
Unit
case Error(err) =>
throw AnormException(err.toString)
}
}
result.left.foreach { t: Seq[Throwable] =>
t.foreach(_.printStackTrace)
t.headOption.foreach { tt => throw tt}
}
}
def f(row: ~[String, Int]) {
println(row._1 + "\t" + row._2)
}
foreach(SQL(query), rowParser, f)
这行得通。但是,我需要将def f(row: (String, Int)) 转换为def f(row: ~[String, String])。如何在我的 f 函数中删除此 ~?这个foreach 函数也需要一行有两列。如何将其推广到 n 列?
【问题讨论】:
-
可以看一下streaming results的文档(Anorm提供了一个Akka Stream模块)
-
我在发布问题之前已经研究过此文档。
-
就像在任何 Anorm 解析器中一样,
~可以表示至少包含两个列的元组结构。您不能“删除”它,而是解析它。 -
感谢信息。知道如何在不将所有数据加载到内存的情况下执行
SQL(query).as(rowParser.*).map(SqlParser.flatten).foreach(println)之类的操作吗? -
宁可使用
.fold