代码如下所示:
case class Supplier(snum: String, sname: String, status: Int, city: String)
class Suppliers(tag: Tag) extends Table[Supplier](tag, "suppliers") {
def snum = column[String]("snum")
def sname = column[String]("sname")
def status = column[Int]("status")
def city = column[String]("city")
def * = (snum, sname, status, city) <> (Supplier.tupled, Supplier.unapply _)
}
val suppliers = TableQuery[Suppliers]
val gr=suppliers.groupBy(_.city).map{ case (k,v) => (k, v) }.buildColl[Set]
当我编译它时,它会抱怨:
Error:(69, 43) No matching Shape found.
Slick does not know how to map the given types.
Possible causes: T in Table[T] does not match your * projection. Or you use an unsupported type in a Query (e.g. scala List).
Required level: scala.slick.lifted.FlatShapeLevel
Source type: (scala.slick.lifted.Column[String], scala.slick.lifted.Query[A$A113.this.Suppliers,A$A113.this.Supplier,[+A]Seq[A]])
Unpacked type: T
Packed type: G
lazy val gr=suppliers.groupBy(_.city).map{ case (k,v) => (k, v) }.buildColl[Set]
^
Error:(69, 43) not enough arguments for method map: (implicit shape: scala.slick.lifted.Shape[_ <: scala.slick.lifted.FlatShapeLevel, (scala.slick.lifted.Column[String], scala.slick.lifted.Query[A$A113.this.Suppliers,A$A113.this.Suppliers#TableElementType,Seq]), T, G])scala.slick.lifted.Query[G,T,Seq].
Unspecified value parameter shape.
lazy val gr=suppliers.groupBy(_.city).map{ case (k,v) => (k, v) }.buildColl[Set]
^
但如果我将case(k,v)=>(k,v)
更改为case(k,v)=>(k,v.length)
,则会再次有效。
有没有人有这方面的想法?
答案 0 :(得分:3)
原因是:Scala的groupBy返回Map[..., Seq[...]]
,换言之,包含其他集合的集合。嵌套的集合!但SQL不支持嵌套集合,它总是返回平面表。支持嵌套集合需要比Slick目前更复杂的从Scala到SQL的转换。因此,Slick禁止这种情况,并要求你让它平坦。例如,case(k,v)=>(k,v.length)
会将其转换为Map[..., Int]
。 Slick通过说Required level: scala.slick.lifted.FlatShapeLevel
来告诉你。
解决方法是在客户端上进行分组,例如suppliers.run.groupBy(_.city)
或在Slick 2.2及更高版本db.run(suppliers).groupBy(_.city).
如果是加入,运行两个查询并在本地加入它们可能会更有效,而不是转移笛卡尔积并在之后进行分组。