【问题标题】:"attempt to use a raw table object" error when using a MappedProjection in a query在查询中使用 MappedProjection 时出现“尝试使用原始表对象”错误
【发布时间】:2013-04-07 17:18:06
【问题描述】:

我试图弄清楚如何在 Slick 中添加带有映射投影的查询,但无论我尝试什么,我都会遇到以下错误:

[error] (run-main) scala.slick.SlickException: 
    Select(TableNode, "USER_NAME") found. This is typically 
    caused by an attempt to use a "raw" table object directly 
    in a query without introducing it through a generator.
scala.slick.SlickException: Select(TableNode, "USER_NAME") 
    found. This is typically caused by an attempt to use a "raw" table 
    object directly in a query without introducing it through a generator.
    at scala.slick.ast.Select.<init>(Node.scala:340)
    at scala.slick.ast.Select.copy(Node.scala:338)
    at scala.slick.ast.Select.nodeRebuild(Node.scala:345)
    at scala.slick.ast.Select.nodeRebuild(Node.scala:338)
    at scala.slick.ast.UnaryNode$class.nodeRebuild(Node.scala:141)
    at scala.slick.ast.Select.nodeRebuild(Node.scala:338)
    at scala.slick.ast.SimpleNode$$anonfun$nodeMapChildren$1.apply(Node.scala:62)
    at scala.slick.ast.SimpleNode$$anonfun$nodeMapChildren$1.apply(Node.scala:62)
    at scala.Option.map(Option.scala:145)
    at scala.slick.ast.SimpleNode$class.nodeMapChildren(Node.scala:62)
    at scala.slick.ast.Select.nodeMapChildren(Node.scala:338)
    at scala.slick.compiler.Inline.scala$slick$compiler$Inline$$tr$1(Inline.scala:67)
    at scala.slick.compiler.Inline$$anonfun$scala$slick$compiler$Inline$$tr$1$3.apply(Inline.scala:67)
    at scala.slick.compiler.Inline$$anonfun$scala$slick$compiler$Inline$$tr$1$3.apply(Inline.scala:67)
    at scala.slick.ast.Node$$anonfun$nodeMapNodes$1.apply(Node.scala:38)
    at scala.slick.ast.Node$$anonfun$nodeMapNodes$1.apply(Node.scala:37)
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
    at scala.slick.ast.Node$class.nodeMapNodes(Node.scala:37)
    at scala.slick.ast.ProductNode$$anon$3.nodeMapNodes(Node.scala:82)
    at scala.slick.ast.SimpleNode$class.nodeMapChildren(Node.scala:62)
    at scala.slick.ast.ProductNode$$anon$3.nodeMapChildren(Node.scala:82)
    at scala.slick.compiler.Inline.scala$slick$compiler$Inline$$tr$1(Inline.scala:67)
    at scala.slick.compiler.Inline$$anonfun$scala$slick$compiler$Inline$$tr$1$3.apply(Inline.scala:67)
    at scala.slick.compiler.Inline$$anonfun$scala$slick$compiler$Inline$$tr$1$3.apply(Inline.scala:67)
    at scala.slick.ast.Node$$anonfun$nodeMapNodes$1.apply(Node.scala:38)
    at scala.slick.ast.Node$$anonfun$nodeMapNodes$1.apply(Node.scala:37)
    at scala.collection.immutable.List.foreach(List.scala:309)
    at scala.slick.ast.Node$class.nodeMapNodes(Node.scala:37)
    at scala.slick.ast.Pure.nodeMapNodes(Node.scala:151)
    at scala.slick.ast.SimpleNode$class.nodeMapChildren(Node.scala:62)
    at scala.slick.ast.Pure.nodeMapChildren(Node.scala:151)
    at scala.slick.compiler.Inline.scala$slick$compiler$Inline$$tr$1(Inline.scala:67)
    at scala.slick.compiler.Inline$$anonfun$scala$slick$compiler$Inline$$tr$1$3.apply(Inline.scala:67)
    at scala.slick.compiler.Inline$$anonfun$scala$slick$compiler$Inline$$tr$1$3.apply(Inline.scala:67)
    at scala.slick.ast.Node$$anonfun$nodeMapNodes$1.apply(Node.scala:38)
    at scala.slick.ast.Node$$anonfun$nodeMapNodes$1.apply(Node.scala:37)
    at scala.collection.immutable.List.foreach(List.scala:309)

我是 Scala 和 Slick 的新手,很难理解消息的含义。我认为这与此有关(取自 slick docs):

请注意,Slick 会在后台克隆您的表对象,因此您不应向它们添加任何额外的状态(不过额外的方法也可以)。还要确保表的实际对象没有定义在静态位置(即在顶层或仅嵌套在其他对象内),因为这可能会在某些情况下由于 scalac 执行的过度优化而导致问题。为您的表使用 val(具有匿名结构类型或单独的类定义)在任何地方都可以。 Lifted Embedding

我已经修改了 slick-examples MultiDBCakeExample 使其看起来像下面的代码,并尝试了几种排列但没有运气。下面的代码取自我的slick-examples project 的分叉版本。这是一个指向 my changes 的链接。

package com.typesafe.slick.examples.lifted

import scala.slick.driver.ExtendedProfile
import scala.slick.session.Session
import scala.slick.driver.H2Driver
import scala.slick.driver.SQLiteDriver

trait Profile {
  val profile: ExtendedProfile
}

case class Picture(url: String, id: Option[Int] = None)

trait PictureComponent { this: Profile => //requires a Profile to be mixed in...
  import profile.simple._ //...to be able import profile.simple._ 

  object Pictures extends Table[(String, Option[Int])]("PICTURES") {
    //                    ^ Table comes from the *current* profile
    def id = column[Option[Int]]("PIC_ID", O.PrimaryKey, O.AutoInc)
    def url = column[String]("PIC_URL", O.NotNull)

    def * = url ~ id

    val autoInc = url returning id into { case (url, id) => Picture(url, id) }

    def insert(picture: Picture)(implicit session: Session): Picture = {
      autoInc.insert(picture.url)
    }
  }
}

case class User(name: String, picture: Picture, id: Option[Int] = None)

case class UserAndPicId(name: String, picId: Int)

trait UserComponent { this: Profile with PictureComponent => //requires Profile and Picture (see def insert)
  import profile.simple._

  object Users extends Table[(String, Int, Option[Int])]("USERS") {
    def id = column[Option[Int]]("USER_ID", O.PrimaryKey, O.AutoInc)
    def name = column[String]("USER_NAME", O.NotNull)
    def pictureId = column[Int]("PIC_ID", O.NotNull)
    def * = name ~ pictureId ~ id
    def justNameAndPicId = name ~ pictureId <> (UserAndPicId, UserAndPicId.unapply _)

    private def autoInc(implicit session: Session) = name ~ pictureId returning id into {
      case (_, id) => id
    }

    def insert(user: User)(implicit session: Session): User = {
      val picture = if (user.picture.id.isEmpty) { //if no picture id...
        Pictures.insert(user.picture) //...insert
      } else user.picture //else return current picture

      val id = autoInc.insert(user.name, picture.id.get)
      user.copy(picture = picture, id = id)
    }

    def userAndPicById = for {
      id <- Parameters[Int]
      user <- this if user.id === id
    } yield justNameAndPicId
  }
}

/**
 * The Data Access Layer contains all components and a profile
 */
class DAL(override val profile: ExtendedProfile) extends UserComponent with PictureComponent with Profile {
  import profile.simple._
  def create(implicit session: Session): Unit = {
    (Users.ddl ++ Pictures.ddl).create //helper method to create all tables
  }
}

/**
 * Run SLICK code with multiple DBMSs using the Cake pattern.
 * Typically this technique can be used to have different DBMS 
 * in production and test (other scenarios are possible as well)
 */
object MultiDBCakeExample {
  // We only need the DB/session imports outside the DAL
  import scala.slick.session.{ Database, Session }

  def run(name: String, dal: DAL, db: Database) {
    import dal._
    import dal.profile.simple._

    println("Running test against " + name)
    db withSession { implicit session: Session =>
      dal.create

      //creating our default picture
      val defaultPic = Pictures.insert(Picture("http://pics/default"))
      println("  Inserted picture: " + defaultPic)

      //inserting users
      val (user1, user2, user3) = (User("name1", defaultPic), User("name2", Picture("http://pics/2")), User("name3", defaultPic))
      println("  Inserted user: " + Users.insert(user1))
      println("  Inserted user: " + Users.insert(user2))
      println("  Inserted user: " + Users.insert(user3))
      println("  All pictures: " + Query(Pictures).list)
      println("  All users : " + Query(Users).list)

      println("  Attempting to fetch UserAndPicId by id")
      Users.userAndPicById(1).firstOption
    }
  }

  def main(args: Array[String]) {
    run("H2", new DAL(H2Driver),
      Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver"))
    run("SQLite", new DAL(SQLiteDriver),
      Database.forURL("jdbc:sqlite::memory:", driver = "org.sqlite.JDBC"))
  }
}

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    问题出在这里:

    def userAndPicById = for {
      id <- Parameters[Int]
      user <- this if user.id === id
    } yield justNameAndPicId
    

    您不能使用this。使用Query(Users)

    【讨论】:

    • 感谢您的提示,但不幸的是,我仍然遇到此更改的相同错误。
    • 你确定吗?当使用 this 代替对象本身时,会发生错误。
    • 我已经实现了您建议的更改,您可以在此处查看:github.com/burma-shave/slick-examples/commit/… 不幸的是,它仍然会引发相同的异常。
    • 更改 for 理解以产生元组 user 确实有效,所以我认为它与映射投影有关。堆栈跟踪引用了一个“选择”节点,这似乎表明它与投影有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 2020-11-06
    相关资源
    最近更新 更多