我有一个后续到另一个油滑的问题,我最近问( 油滑表查询:有认识价值麻烦 )在这里。 请多多包涵!! 我是新来的数据库福和油滑,似乎对文档特别差。 无论如何,我有这个表:
object Users extends Table[(Int, String)]("Users") {
def userId = column[Int]("UserId", O.PrimaryKey, O.AutoInc)
def userName = column[String]("UserName")
def * = userId ~ userName
}
第一部分
我试图用这个功能来查询:
def findByQuery(where: List[(String, String)]) = SlickInit.dbSlave withSession {
val q = for {
x <- Users if foo((x.userId, x.userName), where)
} yield x
q.firstOption.map { case(userId, userName) =>
User(userId, userName)}
}
其中,“哪里”,是搜索查询清单//恩。 ( “用户id”, “1”),( “username” 的, “亚历克斯”) “foo” 的是一个辅助功能,用于测试平等。 我遇到一个类型的错误。
x.userId是类型列[INT]的。 一个人如何可以操纵这个作为一个诠释? 我试图铸造,例如:
foo(x.userId.asInstanceOf[Int]...)
但我也遇到麻烦。 一个人如何处理油滑的返回类型?
第二部分是任何人都熟悉的转换函数:
DEF * =用户id〜userName的<>(用户,User.unapply _)
? 我知道已经有过这个问题,一些优秀的答案,最显着的位置: 斯卡拉光滑方法我不能到目前为止理解和一个非常类似的问题在这里: 映射投影在SLICK同伴对象 。 但是,任何人都可以解释为什么编译器响应
<> method overloaded
对于代码,简单的线条?
让我们先从这个问题:
val q = for {
x <- Users if foo((x.userId, x.userName), where)
} yield x
见,油滑的转变斯卡拉表达式转换成SQL。 为了能够改变的条件下,只要你想,到SQL语句,油滑需要使用一些特殊类型。 在这部分作品类型实际上是改造油滑执行的一部分。
例如,当你写List(1,2,3) filter { x => x == 2 }
的滤波器谓词为列表中的每个元素执行。 但是油滑不能做到这一点! 所以查询[ATable]滤波器{AROW => arow.id === 2}实际上是指 “使与条件ID = 2选择”(我在这里跳过详情)。
我把你的模拟foo
功能和要求油滑生成用于查询的SQL q
:
select x2."UserId", x2."UserName" from "Users" x2 where false
见false
? 这是因为foo
是一个简单的谓词斯卡拉评估为布尔false
。 类似的谓词的查询做的,而不是一个列表,计算到的描述需要在SQL生成做什么。 比较之间的差别filter
S IN列表和油滑:
List[A].filter(A => Boolean):List[A]
Query[E,U].filter[T](f: E => T)(implicit wt: CanBeQueryCondition[T]):Query[E,U]
列表过滤器的计算结果为作为一个列表,而Query.filter评估进入新的查询!
现在,对解决方案的一个步骤。
看来你想要的东西实际上是in
SQL的运营商。 的in
:操作者如果在列表中的一个元素,例如,返回true 4 in (1,2,3,4)
是正确的。 请注意, (1,2,3,4)
是SQL列表 ,而不是元组像斯卡拉。
对于这个用例的in
SQL操作油滑使用操作inSet
。
既然说到了问题的第二部分。 (I改名为where
变量list
,因为where
是油滑方法)
你可以试试:
val q = for {
x <- Users if (x.userId,x.userName) inSet list
} yield x
但是,这不会编译! 这是因为SQL没有元组Scala有方式。 在SQL你不能这样做(1,"Alfred") in ((1,"Alfred"),(2, "Mary"))
记住, (x,y,z)
是列出了SQL语法,我在这里滥用语法只表明它是无效的 - 也有SQL那里的很多方言,有可能他们中的一些支持元组和列表以类似的方式)。
一个可能的解决方案是只使用userId字段:
val q = for {
x <- Users if x.userId inSet list2
} yield x
这产生select x2."UserId", x2."UserName" from "Users" x2 where x2."UserId" in (1, 2, 3)
但因为你明确地使用用户ID和用户名,这是合理的假设用户id不唯一地识别用户。 因此,修改,我们可以连接两个值。 当然,我们需要做同样在列表中。
val list2 = list map { t => t._1 + t._2 }
val q2 = for {
x <- Users if (x.userId.asColumnOf[String] ++ x.userName) inSet list2
} yield x
看看生成的SQL:
select x2."UserId", x2."UserName" from "Users" x2
where (cast(x2."UserId" as VARCHAR)||x2."UserName") in ('1a', '3c', '2b')
看到上面||
? 它在H2Db使用的字符串连接运算符。 H2Db是我使用的运行实例的油滑的驱动程序。 该查询和其他人可以根据你所使用的数据库而有所不同。
希望它澄清有多好作品和解决您的问题。 至少第一个。 :)
第一部分:
油滑用途列[...] - 类型而不是普通Scala的类型。 您还需要定义使用列类型油滑的辅助功能。 您可以实现FOO这样的:
def foo( columns: (Column[Int],Column[String]), values: List[(Int,String)] ) : Column[Boolean] = values.map( value => columns._1 === value._1 && columns._2 === value._2 ).reduce( _ || _ )
还可以阅读pedrofurla的回答,以便更好地了解油滑的作品。
第二部分:
方法<>确实超载,当类型不工作了Scala编译器可以很容易地成为其中超载它应该使用不确定的。 (我们应该摆脱油滑我认为超载的。)写作
def * = userId ~ userName <> (User.tupled _, User.unapply _)
可以稍微改善你的错误消息。 为了解决这个问题,确保列类型的帐户及用户名正好对应于成员类型的用户案例类的,这应该是这个样子case class User( id:Int, name:String )
。 另外,还要确保,你扩展表[用户](不表[(智力,字符串)])当映射到用户。