2015-09-08 4 views
1

У меня есть простая база данных, состоящая из 2-х таблиц - movie и comment, где комментарии, связанные с кино, а потом я следующий кусок Scala anorm код:Scala Anorm от нуля до многих правильный путь

case class Comment(commentId: Long, comment: String) 
case class Movie(movieId: Long, name: String, movieType: String) 

object MovieDao { 
    val movieParser: RowParser[Movie] = { 
    long("movieId") ~ 
    str("name") ~ 
    str("movieType") map { 
     case movieId ~ name ~ movieType => Movie(movieId, name, movieType) 
    } 
    } 

    val commentParser: RowParser[Comment] = { 
    long("commentId") ~ 
    str("comment") map { 
     case commentId ~ comment => Comment(commentId, comment) 
    } 
    } 

    def getAll(movieType: String) = DB.withConnection { 
    implicit connection => 
     SQL(
     """ 
      |SELECT 
      |movie.movieId, 
      |movie.name, 
      |movie.movieType, 
      |comment.commentId, 
      |comment.comment 
      |FROM movie 
      |LEFT JOIN comment USING(movieId) 
      |WHERE movieType = {movieType} 
     """.stripMargin) 
     .on("movieType" -> movieType) 
     .as(((movieParser ~ (commentParser ?)) map (flatten)) *) 
     .groupBy(_._1) map {(mc: (Movie, List[(Movie, Option[Comment])])) => 
     mc match { 
      case (a, b) => (a, b filter { //filter rows with no comments 
      case (c, Some(d)) => true 
      case _ => false 
      } map(_._2)) 
     } 
     } toList 
    } 
} 

Моя цель - вернуть List[(Movie, Option[List[Comment]])] из getAll, поэтому я могу перебирать фильмы и проверять, есть ли какие-либо комментарии как можно более простые, ei соответствие None или Some в списке комментариев. Я в настоящее время возвращаю List[(Movie, Option[List[Option[Comment]])], и я могу только проверить размер списка комментариев (спасибо, используя метод filter), который я не считаю правильным способом сделать это в scala.

Мой второй вопрос заключается в анализе самого запроса, я думаю, что это просто сложно, как я это сделал. Есть ли более простое и приятное решение для разбора отношения 0..N с использованием анорма?

+0

У Anorm нет способа разбора отношений «один ко многим». Я сделал аналогичную вещь в [этом ответе] (http://stackoverflow.com/questions/24315202/flatten-a-list-of-anorm-tuples/24315461#24315461). В конечном итоге я написал [anorm-relational] (https://github.com/mhzajac/anorm-relational), чтобы сократить часть дублирования кода, вызванного этим. (Отказ от ответственности: я являюсь автором этой библиотеки, и она начинает показывать возраст) –

ответ

1

Питер, это, возможно, больше стиля, чем что-либо кардинально разные, но с MovieComments случае класса а, вы могли бы написать что-то вроде:

case class MovieComments(movie: Movie, comments: List[Comment]) 

    val movieCommentsP = 
    movieParser ~ (commentParser ?) map { 
     case movie ~ comment => 
     MovieComments(movie,if (comment.isEmpty) List() else List(comment.get)) 
    } 

    val movieSqlSelector = "m.movieId, m.name, m.movieType" 
    val commentSqlSelector = "c.commentId, c.comment" 

    def getAll(movieType: String) :List[MovieComments]= DB.withConnection { 
    implicit connection => 
     (SQL(
     s""" 
      |SELECT 
      |$movieSqlSelector, 
      |$commentSqlSelector 
      |FROM movie 
      |LEFT JOIN comment USING(movieId) 
      |WHERE movieType = {movieType} 
     """.stripMargin) 
     .on('movieType -> movieType) 
     .as(movieCommentsP *) 
     .groupBy(_.movie.movieId) map { 
      case (movieId,movieComments) => 
       MovieComments(
        movieComments.head.movie, 
        movieComments.flatMap(_.comments)) 
     } 
    ).toList 
    } 

Вы действительно может понадобиться Option[List[Comment]], но бы не List[Comment] делать? List() - это случай «без комментариев». (P.S. Я считаю, что использование переменных sqlSelector помогает при рефакторинге.)

 Смежные вопросы

  • Нет связанных вопросов^_^