2016-01-09 27 views
1

想象一下下列關係油滑3加入查詢一對多關係

一本書包含很多章節,一章只屬於一本書。古典一對多關係。

我模仿它,因爲這:

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> 

我在哪裏可以看到日誌?或者我還需要做些什麼才能看到它們?

回答

3

若要翻譯查詢......

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

...以油滑我們可以filterbooks

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"/> 

我有一個example project with logging set up。您將需要在例如chapter-01文件夾中的xml文件中將INFO更改爲DEBUG

+0

我在'res/main'下創建了.xml文件並找到它,但是日誌在哪裏?它應該去控制檯嗎?我試着用'info'來代替,但我只得到異常,沒有查詢字符串。有什麼我錯過了嗎? – Sorona

+0

另外,謝謝,但它不適合我,我不知道爲什麼。我更新了我的問題。 – Sorona

+1

您需要在XML配置中使用「appender」,並在build.xml中使用日誌記錄庫。這個要點給出了一個SBT依賴和一個完整的日誌配置,應該爲你工作:https://gist.github.com/d6y/fdc780164c044460217b –