scala slick 方法我到目前为止还无法理解

2023-12-08

我尝试去理解一些 Slick 的作品以及它的要求。

这是一个例子:

package models

case class Bar(id: Option[Int] = None, name: String)

object Bars extends Table[Bar]("bar") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)

  // This is the primary key column
  def name = column[String]("name")

  // Every table needs a * projection with the same type as the table's type parameter
  def * = id.? ~ name <>(Bar, Bar.unapply _)
}

有人可以解释一下这样做的目的是什么吗*这里的方法是什么<>, why unapply?什么是投影法~' 返回实例Projection2?


[UPDATE] - 添加了(又一个)解释for理解力

  1. The * method:

    这将返回默认投影- 这就是你的描述:

    '我的所有列(或计算值)usually有兴趣。

    您的表可以有多个字段;你只需要一个子集 您的默认投影。默认投影必须与类型匹配 表的参数。

    让我们一次一个地进行。如果没有<>的东西,只是*:

    // First take: Only the Table Defintion, no case class:
    
    object Bars extends Table[(Int, String)]("bar") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
      def name = column[String]("name")
    
      def * = id ~ name // Note: Just a simple projection, not using .? etc
    }
    
    // Note that the case class 'Bar' is not to be found. This is 
    // an example without it (with only the table definition)
    

    只需一个这样的表定义就可以让您进行如下查询:

    implicit val session: Session = // ... a db session obtained from somewhere
    
    // A simple select-all:
    val result = Query(Bars).list   // result is a List[(Int, String)]
    

    默认投影(Int, String)导致List[(Int, String)]对于诸如此类的简单查询。

    // SELECT b.name, 1 FROM bars b WHERE b.id = 42;
    val q = 
       for (b <- Bars if b.id === 42) 
         yield (b.name ~ 1)
         // yield (b.name, 1) // this is also allowed: 
                              // tuples are lifted to the equivalent projection.
    

    是什么类型的q?它是一个Query与投影(String, Int)。 调用时,它返回一个List of (String, Int)根据投影的元组。

     val result: List[(String, Int)] = q.list
    

    在这种情况下,您已经在中定义了所需的投影yield条款 的for理解。

  2. 现在关于<> and Bar.unapply.

    这提供了所谓的映射投影.

    到目前为止,我们已经了解了如何使用 slick 在 Scala 中表达查询 返回一个柱的投影(或计算值);所以执行时 这些查询你必须考虑结果行一个查询的作为 Scala 元组。 元组的类型将与定义的投影相匹配(由您定义)for理解如前面的例子,默认情况下*投影)。 这就是为什么field1 ~ field2返回的投影Projection2[A, B] where A是类型field1 and B是类型field2.

    q.list.map {
      case (name, n) =>  // do something with name:String and n:Int
    }
    
    Queury(Bars).list.map {
      case (id, name) =>  // do something with id:Int and name:String 
    }
    

    我们正在处理元组,如果元组太多,这可能会很麻烦 列。我们希望将结果视为TupleN而是一些 具有命名字段的对象。

    (id ~ name)  // A projection
    
    // Assuming you have a Bar case class:
    case class Bar(id: Int, name: String) // For now, using a plain Int instead
                                          // of Option[Int] - for simplicity
    
    (id ~ name <> (Bar, Bar.unapply _)) // A MAPPED projection
    
    // Which lets you do:
    Query(Bars).list.map ( b.name ) 
    // instead of
    // Query(Bars).list.map { case (_, name) => name }
    
    // Note that I use list.map instead of mapResult just for explanation's sake.
    

    这是如何运作的?<>进行投影Projection2[Int, String]和 返回类型上的映射投影Bar。两个论点Bar, Bar.unapply _告诉光滑这是怎么回事(Int, String)投影必须映射到案例类。

    这是一个双向映射;Bar是案例类构造函数,所以这就是 需要的信息来自(id: Int, name: String) to a Bar. And unapply如果你猜到了,那就是相反的。

    哪里有unapply来自?这是一个标准的 Scala 方法,可用于 任何普通的案例类 - 只是定义Bar给你一个Bar.unapply哪个 是一个提取器可以用来取回id and nameBar是用:

    val bar1 = Bar(1, "one")
    // later
    val Bar(id, name) = bar1  // id will be an Int bound to 1,
                              // name a String bound to "one"
    // Or in pattern matching
    val bars: List[Bar] = // gotten from somewhere
    val barNames = bars.map {
      case Bar(_, name) => name
    }
    
    val x = Bar.unapply(bar1)  // x is an Option[(String, Int)]
    

    因此,您的默认投影可以映射到您最期望使用的案例类:

    object Bars extends Table[Bar]("bar") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
      def name = column[String]("name")
      def * = id ~ name <>(Bar, Bar.unapply _)
    }
    

    或者你甚至可以在每个查询中使用它:

    case class Baz(name: String, num: Int)
    
    // SELECT b.name, 1 FROM bars b WHERE b.id = 42;
    val q1 = 
       for (b <- Bars if b.id === 42) 
         yield (b.name ~ 1 <> (Baz, Baz.unapply _))
    

    这里的类型是q1 is a Query with a mapped投影到Baz。 调用时,它返回一个List of Baz对象:

     val result: List[Baz] = q1.list
    
  3. 最后,顺便说一句,.? offers 选项提升- Scala 方式 处理可能不存在的价值观。

     (id ~ name)   // Projection2[Int, String] // this is just for illustration
     (id.? ~ name) // Projection2[Option[Int], String]
    

    总结起来,这将与您最初的定义很好地配合Bar:

    case class Bar(id: Option[Int] = None, name: String)
    
    // SELECT b.id, b.name FROM bars b WHERE b.id = 42;
    val q0 = 
       for (b <- Bars if b.id === 42) 
         yield (b.id.? ~ b.name <> (Bar, Bar.unapply _))
    
    
    q0.list // returns a List[Bar]
    
  4. 回应关于 Slick 如何使用的评论for理解:

    不知何故,单子总是设法出现并要求 成为解释的一部分...

    因为理解不仅仅特定于集合。 它们可以用于任何类型的Monad,集合是 只是 Scala 中可用的多种 monad 类型之一。

    但随着系列的熟悉,它们有了一个良好的开端 解释点:

    val ns = 1 to 100 toList; // Lists for familiarity
    val result = 
      for { i <- ns if i*i % 2 == 0 } 
        yield (i*i)
    // result is a List[Int], List(4, 16, 36, ...)
    

    在 Scala 中,for 理解式是 for 的语法糖 method(可能是嵌套的)方法调用:上面的代码 (或多或少)相当于:

    ns.filter(i => i*i % 2 == 0).map(i => i*i)
    

    基本上,任何与filter, map, flatMap方法(换句话说,Monad)可以用在for理解代替ns。一个很好的例子 是个选项单子。这是前面的例子 哪里相同for声明适用于ListOption monads:

    // (1)
    val result = 
      for { 
        i <- ns          // ns is a List monad
        i2 <- Some(i*i)  // Some(i*i) is Option
          if i2 % 2 == 0 // filter
      } yield i2
    
    // Slightly more contrived example:
    def evenSqr(n: Int) = { // return the square of a number 
      val sqr = n*n         // only when the square is even
      if (sqr % 2 == 0) Some (sqr)
      else None
    }
    
    // (2)
    result = 
      for { 
        i <- ns  
        i2 <- evenSqr(i) // i2 may/maynot be defined for i!
      } yield i2
    

    在最后一个例子中,转换可能看起来像 像这样:

    // 1st example
    val result = 
      ns.flatMap(i => Some(i*i)).filter(i2 => i2 %2 ==0)
    
    // Or for the 2nd example
    result = 
      ns.flatMap(i => evenSqr(i)) 
    

    在 Slick 中,查询是一元的 - 它们只是带有 这map, flatMap and filter方法。所以for理解 (在解释中显示*方法)只是翻译为:

    val q = 
      Query(Bars).filter(b => b.id === 42).map(b => b.name ~ 1)
    // Type of q is Query[(String, Int)]
    
    val r: List[(String, Int)] = q.list // Actually run the query
    

    如你看到的,flatMap, map and filter用于 生成一个Query通过反复变换Query(Bars)每次调用filter and map。如果是 集合这些方法实际上迭代并过滤集合 但在 Slick 中它们用于生成 SQL。更多详细信息请参见此处:Scala Slick 如何将 Scala 代码转换为 JDBC?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

scala slick 方法我到目前为止还无法理解 的相关文章

随机推荐

  • Gradle 依赖项中的重复类

    我正在构建一个 Android 应用程序 并使用 recaptcha 和 easywsdl 存储库 这两个存储库都包含 okhttp 和 okio jar 并且在启动存在重复类的应用程序时出现错误 然而 这些并不相同 如果我从项目中排除 o
  • YouTube API 用于获取频道上的所有视频

    我们需要一个按 YouTube 频道名称排列的视频列表 使用 API 我们可以使用以下 API 获取频道列表 仅频道名称 https gdata youtube com feeds api channels v 2 q tendulkar
  • 在模态上滚动时防止触摸设备上的主体滚动

    我正在开发一个网络应用程序 该应用程序使用大量模态叠加层以及模态中的可滚动内容 在触摸设备上 特别是在 Android 上 移动浏览器希望滚动模式后面的正文内容 而不是模式内的实际可滚动内容区域 或者 如果内容确实滚动 当它到达可滚动区域的
  • 将 byte[] 转换为图像

    我已将图像上传到我的数据库中byte 现在我想把它展示出来 出现错误 用户代码未处理参数异常Parameter is not valid 在这一行 newImage System Drawing Image FromStream strea
  • 使用 JSoup 从表中提取数据

    我想使用 JSoup 框架提取该表 以将内容保存在 表 数组中 第一个 tr 标签是表头 以下所有内容 不包括在内 描述了该内容 table width 100 cellspacing 0 cellpadding 4 border 1 tr
  • 只允许图像FILE_UPLOAD

    基本上下面的代码只允许图片通过我添加的 mov and mp4到允许列表 但上传时它仍然输出该文件不是图像 只是想知道我哪里出了问题 帖子及形式
  • 如何使用手柄在android中缩放视图?

    我正在尝试实现一个手柄来缩放 android 中的视图 我不想使用多点触控之类的东西 而是希望能够仅用一根手指来调整图像大小 这是我的活动代码 我觉得好像我非常接近 但有五件事无法正常工作 缩放已关闭 它的增长速度比应有的要快得多 Solv
  • 在运行时确定泛型方法参数的类型

    给定一个具有以下结构的类 我试图确定泛型方法的调用者分配的参数 T 的类型 public class MyClass public
  • 使用 GKMatch 的 Game Center 多人游戏但似乎无法连接

    大家好 我是 iOS 游戏中心的新人 我正在尝试将使用匹配的多人游戏功能添加到我的游戏中并遵循文档 到目前为止 我的 2 个客户端可以成功获得匹配 即调用 matchmakerViewController didFindMatch 回调并传
  • 使用 Google Apps 脚本将数据从数组复制/推送到工作表范围,一次一行

    我在原始表上使用 getValues 创建了一个多维数组sheetValues 我想将sheetValues数组中的值复制到目标工作表中 如何将sheetValues数组每行的内容推送到目标工作表中 什么函数允许我将数组的每一行一次一行 检
  • 如何知道我在 Windows 批处理文件中连接的是哪个 SSID?

    目前 我有 2 个批处理文件 可以使用注册表编辑器打开和关闭代理 Like reg add HKCU Software Microsoft Windows CurrentVersion Internet Settings v ProxyEn
  • java 9未命名模块在调试时从两者读取包[X](使用IntelliJ)

    在我的项目中 我有一个使用多个第三方库的包 让我们看一下依赖树 INFO commons logging commons logging jar 1 2 compile INFO org apache directory studio or
  • id:css中的悬停id?是否可以?

    这是我的 html 代码 div div div div div div div div 这是我的 CSS 代码 这个悬停为什么不起作用 谁来帮帮我 我需要当我悬停 id 1时 将更改背景颜色 id 2 因为这些 div
  • XTS 将函数应用于一天中的时间子集?

    如何将汇总函数应用于一天中的时间子集 例如 r T16 00 T17 00 Value 我怎样才能应用类似的东西function x quantile x c 90 每天样本小时的价值 您可以使用apply daily在完成一天中的时间子集
  • 正则表达式匹配空格,但不在“字符串”中

    仅当空格未用双引号 括起来时 我才会查找匹配空格的正则表达式 例如 在 Mary had a little lamb 它应该匹配第一个和第二个空格 但不匹配其他空格 我想分割字符串only不在双引号内的空格处 也不在引号处 我正在使用 C
  • 有没有更快的 CountIF

    正如标题所说 是否有任何函数或 VBA 代码可以执行与 countif 相同的功能并且速度更快 目前正处于大规模计数阶段 它正在耗尽我的 CPU 它只是工作表中的基本计数 不在 VBA 中 countif X X Y 然而 名单非常庞大 所
  • 模拟器总是崩溃并显示错误“等待设备时出错:AVD 的模拟器进程已终止”

    我现在被困在假设它的硬件上 但没有太大意义 因为它以前可以工作 并且突然停止了 昨天一整天 当尝试在任何设备 任何 api 任何应用程序中打开模拟器 包括仅打开模拟器本身 时 我收到此崩溃消息 我尝试过卸载并安装 android studi
  • 在 Apache Spark Python 中自定义 K-means 距离公式

    现在我使用 K means 进行聚类和跟踪本教程 and API 但我想使用自定义公式来计算距离 那么如何使用 PySpark 在 k means 中传递自定义距离函数呢 一般来说 使用不同的距离度量没有意义 因为 k 均值 与k 中心点
  • 尝试使用 NDK 构建 PocketSphinxAndroidDemo 时出现问题

    我正在尝试编译 PocketSphinxAndroidDemo 它提供了 Android 上 CMU pocketsphinx 语音识别器的示例实现 我首先收到类似于讨论的错误here 执行 ndk build 后 出现以下错误 Gdbse
  • scala slick 方法我到目前为止还无法理解

    我尝试去理解一些 Slick 的作品以及它的要求 这是一个例子 package models case class Bar id Option Int None name String object Bars extends Table B