使用 Slick 通过一个查询生成一页新闻
generate a page of news with one query with Slick
我想通过一个查询生成一页带有相关标签的新闻。但我做不对。我不明白的是为什么根据 Idea 编辑器和编译器,错误行上方的行是正确的。
val newsTable = TableQuery[NewsTable]
val newsTagsTable = TableQuery[NewsTags]
val newsTagsAssociationsTable = TableQuery[newsTagsAssociations]//2 columns: newsId and tagId
case class FullNews(news:Option[News],tags:Seq[NewsTag])
def getPage(page: Long = 0, pageSize: Int = 10): Future[Page[FullNews]] = {
val offset = pageSize * page
val total = newsTable.size.result
val selectedNews = newsTable.sortBy(x => x.id.desc).drop(offset).take(pageSize)
val fullNews = selectedNews.result.map(a => a.map(news => {
val tagsId = newsTagsAssociationsTable.filter(x => x.idNews === news.id).map(_.idTag)
val tagsQuery = newsTagsTable.filter(tag => tag.id in tagsId)
for (tags <- tagsQuery .result) yield FullNews(Some(news), tags)
}))
val theFullNews: Future[Seq[FullNews]] = db.run(fullNews )//error at this line
val totalFuture = db.run(total)
for (
newsSeq <- theFullNews;
t <- totalFuture
) yield Page[FullNews](newsSeq, page, offset, t, pageSize)
}
游戏编译器说:
Blockquote
type mismatch;
[error] found : slick.dbio.DBIOAction[Seq[slick.dbio.DBIOAction[models.FullNews,slick.dbio.NoStream,slick.dbio.Effect.Read]],slick.dbio.NoStream,slick.dbio.Effect.Read]
[error] required: slick.dbio.DBIOAction[Seq[models.FullNews],slick.dbio.NoStream,Nothing]
提前致谢。
您的用例通常通过使用连接来解决。我假设并非每个 news
都有 tags
。这就是我要使用 outer join
的原因。未经测试的代码:
// FullNews always has a news, right? Removed option type.
case class FullNews(news: News, tags: Seq[NewsTag])
def getPage(page: Long = 0, pageSize: Int = 10): Future[Page[FullNews]] = {
val offset = pageSize * page
// let's query fullNews first.
// fullNews is basically Query[Seq[News, Option[NewsTag]]]
val fullNews = newsTable.sortBy(x => x.id.desc).drop(offset).take(pageSize)
.joinLeft(newsTagsAssociationsTable).on(_.id === _.newsId)
.joinLeft(newsTagsTable).on(_._2.map(_.tagId) === _.id)
.map {
case ((news, _), tag) => (news, tag)
}
// query the total size
val totalNews = newsTable.size
// Now that we have our queries in place, create an action
// and map the result to FullNews:
val fullNewsAction = fullNews.result.map { result =>
result.groupBy(_._1).map {
case (news, grp) => FullNews(news, grp.flatMap(_._2).distinct)
}
}
// For the sake of completeness, let's also create an action for totalNews
val totalNewsAction = totalNews.result
// Compose an action consisting of fullNewsAction and totalNewsAction
val pageAction = for {
n <- fullNewsAction
t <- totalNewsAction
} yield Page(n, page, offset, t, pageSize)
// Finally execute pageAction on the db
db.run(pageAction.transactionally)
}
如果每个 news
至少有一个 tag
关联,您可以将外部联接替换为内部联接。有关详细信息,请参阅 slick docs。
我想通过一个查询生成一页带有相关标签的新闻。但我做不对。我不明白的是为什么根据 Idea 编辑器和编译器,错误行上方的行是正确的。
val newsTable = TableQuery[NewsTable]
val newsTagsTable = TableQuery[NewsTags]
val newsTagsAssociationsTable = TableQuery[newsTagsAssociations]//2 columns: newsId and tagId
case class FullNews(news:Option[News],tags:Seq[NewsTag])
def getPage(page: Long = 0, pageSize: Int = 10): Future[Page[FullNews]] = {
val offset = pageSize * page
val total = newsTable.size.result
val selectedNews = newsTable.sortBy(x => x.id.desc).drop(offset).take(pageSize)
val fullNews = selectedNews.result.map(a => a.map(news => {
val tagsId = newsTagsAssociationsTable.filter(x => x.idNews === news.id).map(_.idTag)
val tagsQuery = newsTagsTable.filter(tag => tag.id in tagsId)
for (tags <- tagsQuery .result) yield FullNews(Some(news), tags)
}))
val theFullNews: Future[Seq[FullNews]] = db.run(fullNews )//error at this line
val totalFuture = db.run(total)
for (
newsSeq <- theFullNews;
t <- totalFuture
) yield Page[FullNews](newsSeq, page, offset, t, pageSize)
}
游戏编译器说:
Blockquote type mismatch; [error] found : slick.dbio.DBIOAction[Seq[slick.dbio.DBIOAction[models.FullNews,slick.dbio.NoStream,slick.dbio.Effect.Read]],slick.dbio.NoStream,slick.dbio.Effect.Read] [error] required: slick.dbio.DBIOAction[Seq[models.FullNews],slick.dbio.NoStream,Nothing]
提前致谢。
您的用例通常通过使用连接来解决。我假设并非每个 news
都有 tags
。这就是我要使用 outer join
的原因。未经测试的代码:
// FullNews always has a news, right? Removed option type.
case class FullNews(news: News, tags: Seq[NewsTag])
def getPage(page: Long = 0, pageSize: Int = 10): Future[Page[FullNews]] = {
val offset = pageSize * page
// let's query fullNews first.
// fullNews is basically Query[Seq[News, Option[NewsTag]]]
val fullNews = newsTable.sortBy(x => x.id.desc).drop(offset).take(pageSize)
.joinLeft(newsTagsAssociationsTable).on(_.id === _.newsId)
.joinLeft(newsTagsTable).on(_._2.map(_.tagId) === _.id)
.map {
case ((news, _), tag) => (news, tag)
}
// query the total size
val totalNews = newsTable.size
// Now that we have our queries in place, create an action
// and map the result to FullNews:
val fullNewsAction = fullNews.result.map { result =>
result.groupBy(_._1).map {
case (news, grp) => FullNews(news, grp.flatMap(_._2).distinct)
}
}
// For the sake of completeness, let's also create an action for totalNews
val totalNewsAction = totalNews.result
// Compose an action consisting of fullNewsAction and totalNewsAction
val pageAction = for {
n <- fullNewsAction
t <- totalNewsAction
} yield Page(n, page, offset, t, pageSize)
// Finally execute pageAction on the db
db.run(pageAction.transactionally)
}
如果每个 news
至少有一个 tag
关联,您可以将外部联接替换为内部联接。有关详细信息,请参阅 slick docs。