簡體   English   中英

光滑3聯接查詢一對多關系

[英]Slick 3 join query one to many relationship

想象以下關系

一本書由許多章組成,一章恰好屬於一本書。 經典的一對多關系。

我將其建模為:

case class Book(id: Option[Long] = None, order: Long, val title: String)

class Books(tag: Tag) extends Table[Book](tag, "books")
{
  def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
  def order = column[Long]("order")
  def title = column[String]("title")

  def * = (id, order, title) <> (Book.tupled, Book.unapply)
  def uniqueOrder = index("order", order, unique = true)

  def chapters: Query[Chapters, Chapter, Seq] = Chapters.all.filter(_.bookID === id)
}

object Books
{
  lazy val all = TableQuery[Books]
  val findById = Compiled {id: Rep[Long] => all.filter(_.id === id)}

  def add(order: Long, title: String) = all += new Book(None, order, title)
  def delete(id: Long) = all.filter(_.id === id).delete

//  def withChapters(q: Query[Books, Book, Seq]) = q.join(Chapters.all).on(_.id === _.bookID)

  val withChapters = for
  {
    (Books, Chapters) <- all join Chapters.all on (_.id === _.bookID)
  } yield(Books, Chapters)
}

case class Chapter(id: Option[Long] = None, bookID: Long, order: Long, val title: String)

class Chapters(tag: Tag) extends Table[Chapter](tag, "chapters")
{
  def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
  def bookID = column[Long]("book_id")
  def order = column[Long]("order")
  def title = column[String]("title")

  def * = (id, bookID, order, title) <> (Chapter.tupled, Chapter.unapply)
  def uniqueOrder = index("order", order, unique = true)

  def bookFK = foreignKey("book_fk", bookID, Books.all)(_.id.get, onUpdate = ForeignKeyAction.Cascade, onDelete = ForeignKeyAction.Restrict)
}

object Chapters
{
  lazy val all = TableQuery[Chapters]
  val findById = Compiled {id: Rep[Long] => all.filter(_.id === id)}

  def add(bookId: Long, order: Long, title: String) = all += new Chapter(None, bookId, order, title)
  def delete(id: Long) = all.filter(_.id === id).delete
}

現在我要做的是:

我想查詢所有或特定書籍(按ID) 及其所有章節

轉換為普通SQL,類似:

SELECT * FROM books b JOIN chapters c ON books.id == c.book_id WHERE books.id = 10

但是在Slick中,我無法真正完成整個工作。

我試過的

object Books
{
    //...
    def withChapters(q: Query[Books, Book, Seq]) = q.join(Chapters.all).on(_.id === _.bookID)
}

以及:

object Books
{
    //...
    val withChapters = for
    {
        (Books, Chapters) <- all join Chapters.all on (_.id === _.bookID)
    } yield(Books, Chapters)
}

但無濟於事。 (我使用ScalaTest並得到一個空結果(對於def withChapters(...) )或val withChapters = for...另一個異常)

怎么繼續呢? 我試圖保留文檔,但是顯然我做錯了。

另外:有沒有一種簡單的方法可以將實際查詢視為字符串? 我只找到了query.selectStatement之類的東西,但不適用於我加入的查詢。 對於調試以查看實際查詢是否錯誤將非常有用。

編輯:我的測試如下所示:

class BookWithChapters extends FlatSpec with Matchers with ScalaFutures with BeforeAndAfter
{
  val db = Database.forConfig("db.test.h2")

  private val books = Books.all
  private val chapters = Chapters.all

  before { db.run(setup) }
  after {db.run(tearDown)}

  val setup = DBIO.seq(
    (books.schema).create,
    (chapters.schema).create
  )

  val tearDown = DBIO.seq(
    (books.schema).drop,
    (chapters.schema).drop
  )

  "Books" should "consist of chapters" in
  {
    db.run(
      DBIO.seq
      (
        Books.add(0, "Book #1"),
        Chapters.add(0, 0, "Chapter #1")
      )
    )

    //whenReady(db.run(Books.withChapters(books).result)) {
    whenReady(db.run(Books.withChapters(1).result)) {
    result => {
      //  result should have length 1
        print(result(0)._1)
      }
    }
  }
}

這樣,我得到一個IndexOutOfBoundsException

我用它作為我的方法:

object Books
{
      def withChapters(id: Long) = Books.all.filter(_.id === id) join Chapters.all on (_.id === _.bookID)
}

也:

logback.xml看起來像這樣:

<configuration>
    <logger name="slick.jdbc.JdbcBackend.statement" level="DEBUG/>
</configuration>

我在哪里可以看到日志? 或者我還必須做什么才能看到它們?

要翻譯您的查詢...

SELECT * FROM books b JOIN chapters c ON books.id == c.book_id WHERE books.id = 10

...對於Slick,我們可以filter books

val bookTenChapters = 
  Books.all.filter(_.id === 10L) join Chapters.all on (_.id === _.bookID)

這將為您提供一個返回Seq[(Books, Chapters)] 如果要選擇其他書籍,則可以使用其他過濾器表達式。

或者,您可能希望過濾聯接:

val everything = 
   Books.all join Chapters.all on (_.id === _.bookID)

val bookTenChapters = 
  everything.filter { case (book, chapter) => book.id === 10L }

那可能更接近您的加入。 檢查使用您的數據庫生成的SQL,以查看您喜歡的數據庫。

您可以通過創建src/main/resources/logback.xml文件並設置以下內容來記錄查詢:

 <logger name="slick.jdbc.JdbcBackend.statement" level="DEBUG"/>

我有一個建立日志記錄示例項目 您將需要將xml文件(例如,Chapter-01文件夾)中的INFO更改為DEBUG

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM