Slick 3:如何丢弃和接收具有某些关系的集合

Posted

技术标签:

【中文标题】Slick 3:如何丢弃和接收具有某些关系的集合【英文标题】:Slick 3: how to drop and take on collections with some relations 【发布时间】:2015-11-10 15:20:36 【问题描述】:

我正在与 Play 合作! Scala 2.4 和 Slick 3。 我有如下多对多关系:

  class Artists(tag: Tag) extends Table[Artist](tag, "artists") 
    def id = column[Long]("artistid", O.PrimaryKey, O.AutoInc)
    def name = column[String]("name")

     def * = (id.?, name) <> ((Artist.apply _).tupled, Artist.unapply)
  

关系表:

  class ArtistsGenres(tag: Tag) extends Table[ArtistGenreRelation](tag, "artistsgenres") 
    def artistId = column[Long]("artistid")
    def genreId = column[Int]("genreid")

    def * = (artistId, genreId) <> ((ArtistGenreRelation.apply _).tupled, ArtistGenreRelation.unapply)

    def aFK = foreignKey("artistid", artistId, artists)(_.id, onDelete = ForeignKeyAction.Cascade)
    def bFK = foreignKey("genreid", genreId, genres)(_.id, onDelete = ForeignKeyAction.Cascade)
  

还有第三张表:

 class Genres(tag: Tag) extends Table[Genre](tag, "genres") 
    def id = column[Int]("genreid", O.PrimaryKey, O.AutoInc)
    def name = column[String]("name")

    def * = (id.?, name) <> ((Genre.apply _).tupled, Genre.unapply)
  

到目前为止,我只想按以下流派名称获取所有艺术家(以及他们的流派):

  def findAllByGenre(genreName: String, offset: Int, numberToReturn: Int): Future[Seq[ArtistWithGenre]] = 
    val query = for 
      genre <- genres if genre.name === genreName
      artistGenre <- artistsGenres if artistGenre.genreId === genre.id
      artist <- artists joinLeft
        (artistsGenres join genres on (_.genreId === _.id)) on (_.id === _._1.artistId)

      if artist._1.id === artistGenre.artistId
     yield artist


    db.run(query.result) map  seqArtistAndOptionalGenre => 
        ArtistsAndOptionalGenresToArtistsWithGenres(seqArtistAndOptionalGenre)
    
  

方法 ArtistsAndOptionalGenresToArtistsWithGenres 按艺术家对响应进行分组。这就像一个魅力。现在我想限制从数据库中获取的艺术家数量。

但我无法正确使用光滑的函数takedrop:确实,当我的查询返回艺术家和关系列表时,如果我在.result 之前添加take,我不会' t 收到我想获得的艺术家数量(取决于艺术家的关系数量)。

在我按艺术家对结果进行分组之后,我可以放弃并接受,但我在这里看到一个问题:SGBDR 不会优化请求,即我会得到所有艺术家(可能很多),继续groupBy 和 after 取一点而不是限制 groupBy 之前返回的艺术家的数量。

【问题讨论】:

【参考方案1】:

我找到了以下解决方案(有 2 个查询,但有 1 个 DB 调用):

def findAllByGenre(genreName: String, offset: Int, numberToReturn: Int): Future[Seq[ArtistWithWeightedGenres]] = 
    val query = for 
      genre <- genres.filter(_.name === genreName)
      artistGenre <- artistsGenres.filter(_.genreId === genre.id)
      artist <- artists.filter(_.id === artistGenre.artistId)

     yield artist

    val artistsIdFromDB = query.drop(offset).take(numberToReturn) map (_.id)

    val query2 = for 
      artistWithGenres <- artists.filter(_.id in artistsIdFromDB) joinLeft
        (artistsGenres join genres on (_.genreId === _.id)) on (_.id === _._1.artistId)
     yield artistWithGenres

    db.run(query2.result) map  seqArtistAndOptionalGenre =>
      ArtistsAndOptionalGenresToArtistsWithGenres(seqArtistAndOptionalGenre)
     map(_.toVector)
  

如果有人有更好的解决方案...

【讨论】:

以上是关于Slick 3:如何丢弃和接收具有某些关系的集合的主要内容,如果未能解决你的问题,请参考以下文章

Slick 3 多对多关系:如何获取表的所有元素及其关系(如果存在)?

浅谈Slick- 基本功能描述

ConnectionManager.onChannelMessage() 接收到具有不同 connectionSerial 的消息,但消息 id 与上一个相同;丢弃

如何使用嵌套元组或 HList 处理具有 Slick 的 > 22 列表?

集合的包含与真包含概念

如何使用Python随机丢弃集合中的多个元素?