Sql 什么';在Slick 3.0中,将分页和非查询分组结合起来的好方法是什么?
为了简化,假设我有三个表:Sql 什么';在Slick 3.0中,将分页和非查询分组结合起来的好方法是什么?,sql,scala,slick,slick-3.0,Sql,Scala,Slick,Slick 3.0,为了简化,假设我有三个表: val postTable = TableQuery[Posts] val postTagTable = TableQuery[PostTags] val tagTable = TableQuery[Tags] 一篇文章可以有多个标记,postTagTable只包含关系 现在我可以像这样查询帖子和标签: val query = for { post <- postTable postTag <- postTagTable if post.
val postTable = TableQuery[Posts]
val postTagTable = TableQuery[PostTags]
val tagTable = TableQuery[Tags]
一篇文章可以有多个标记,postTagTable
只包含关系
现在我可以像这样查询帖子和标签:
val query = for {
post <- postTable
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)
val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
def findPagination(from: Int, to: Int): Future[Seq[(Post, Seq[Tag])]] = {
val query:DBIO[Seq[(Album,Seq[Genre])]] = postRepository.findAll(from, to).flatMap{posts=>
DBIO.sequence(
posts.map{ post=>
tagRepository.findByPostId(post.id).map(tags=>(post,tags))
}
)
}
db.run(query)
}
但这显然会导致嵌套查询。这就是我想要避免的
编辑2
另一个可能的双查询解决方案:
val pageQuery = postTable drop(page * pageSize) map(_.id) take(pageSize)
db.run(pageQuery.result) flatMap {
case ids: Seq[Int] =>
val query = for {
post <- postTable if post.id inSetBind ids
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)
val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
}
val pageQuery=postTable drop(page*pageSize)map(u.id)take(pageSize)
db.run(pageQuery.result)flatMap{
案例ID:Seq[Int]=>
val query=for{
post您可以这样做:
val query = for {
post <- postTable
postTag <- postTagTable if post.id === postTag.postId
tag <- tagTable if postTag.tagId === tag.id
} yield (post, tag)
val postTags = db.run(query.result).map {
case result: Seq[(Post,Tag)] =>
result.groupBy(_._1).map {
case (post, postTagSeq) => (post, postTagSeq.map(_._2))
}
}
def findPagination(from: Int, to: Int): Future[Seq[(Post, Seq[Tag])]] = {
val query:DBIO[Seq[(Album,Seq[Genre])]] = postRepository.findAll(from, to).flatMap{posts=>
DBIO.sequence(
posts.map{ post=>
tagRepository.findByPostId(post.id).map(tags=>(post,tags))
}
)
}
db.run(query)
}
内部PostRepository
def findAll(from: Int, limit: Int): DBIO[Seq[Post]] = postTable.drop(from).take(limit).result
def findByPostId(id: Int): DBIO[Seq[Tag]] = {
val query = for {
tag <- tagTable
pstTag <- postTagTable if pstTag.postId === id && tag.id === pstTag.tagId
} yield tag
query.result
}
内部TagRepository
def findAll(from: Int, limit: Int): DBIO[Seq[Post]] = postTable.drop(from).take(limit).result
def findByPostId(id: Int): DBIO[Seq[Tag]] = {
val query = for {
tag <- tagTable
pstTag <- postTagTable if pstTag.postId === id && tag.id === pstTag.tagId
} yield tag
query.result
}
也许在您的情况下,预编译这个查询更有效
我也有同样的问题。可能还很有趣:
val query = for {
((p, pt), t) <- posts.filter({x => x.userid === userId}).sortBy({x=>x.createdate.desc}).take(count).
joinLeft (postsTags).on((x, y)=>x.postid === y.postid).
joinLeft (tags).on(_._2.map(_.tagid) === _.tagid)
} yield (p.?, t.map(_.?))
//val query = posts filter({x => x.userid === userId}) sortBy({x=>x.createdate.desc}) take(count)
try db.run(query result)
catch{
case ex:Exception => {
log error("ex:", ex)
Future[Seq[(Option[PostsRow], Option[Option[TagsRow]])]] {
Seq((None, None))
}
}
}
}
它返回如下顺序:
Seq[(Post,Seq[Tag]),(Post,Seq[Tag])…]在这种情况下,Slick的groupBy
没有帮助吗?如果你在查询中按Post进行groupBy
,然后按Post进行take
?如果我在查询中按groupBy,我需要使用map来聚合我没有分组的所有内容。因此,如果我要在Post上分组(在查询中),我无法将标记作为列表获取,但只能对它们进行计数。但即使它只命中数据库一次,也会导致n+1个语句(其中n是pageSize),不是吗?是的,您对数据库的命中率为n+1。1命中率为“分页”posts和n用于获取每个postOK的标记,因此您可以避免嵌套查询,但对数据库进行两次往返更糟糕