Play framework 2.0 のためのブログです。
3月
20
Comments


Slick2.1にて、ManyToMany(多対多)を実現する方法例
今回の実装では、User *---* Project というリレーションを実現します。

  1. val user = Users.findById(1).get  
  2. val projects = user.projects // SQL走る  
  3. val projects2 = user.projects // ここでは、キャッシュされた結果が返るためSQLは走らない  

上記のように、アクセス可能で、初期アクセス時のみにSQLが発行されるような使用としています。

■Dao.scala
  1. package models  
  2.   
  3. import scala.slick.lifted.TableQuery  
  4.   
  5. private[models] trait DAO {  
  6.   val Users = TableQuery[Users]  
  7.   val Projects = TableQuery[Projects]  
  8.   val ProjectUserMap = TableQuery[ProjectUserMap]  
  9. }  

■User.scala
  1. package models  
  2.   
  3. import java.sql.Timestamp  
  4. import play.api.db.slick.Config.driver.simple._  
  5.   
  6. // define dto  
  7. case class User(id: Long, name: String){  
  8.   // ##############################  
  9.   //  user.projects という形で、アクセス可能  
  10.   //  また、キャッシュされるため、2度めのアクセスの際にはSQLは走らない  
  11.   // ##############################  
  12.   val projectCache = collection.mutable.Map[Long, List[Product]]()  
  13.   def projects(implicit session: Session) = {  
  14.     projectCache.getOrElseUpdate(this.id, ProjectUserMap.projects(this.id))  
  15.   }  
  16. }  
  17.   
  18. // define table schema  
  19. class Users(tag: Tag) extends Table[User](tag, "users"with DAO{  
  20.   def id = column[Long]("id", O.PrimaryKey, O.AutoInc)  
  21.   def name = column[String]("name", O.NotNull)  
  22.   def * = (id, name) <> (User.tupled, User.unapply)  
  23.   def idx = index("idx_token", token ,unique = true)  
  24. }  
  25.   
  26. object Users extends DAO {  
  27.   def findById(id: Long)(implicit s: Session): Option[User] = {  
  28.     Users.filter { _.id === id }.firstOption  
  29.   }  
  30.   
  31.   def insert(user: User)(implicit s: Session) {  
  32.     Users += user  
  33.   }  
  34. }  
■Project.scala
  1. package models  
  2.   
  3. import java.sql.Timestamp  
  4. import play.api.db.slick.Config.driver.simple._  
  5.   
  6. // define dto  
  7. case class Project(id: Long, name: String, description: String){  
  8.   // ##############################  
  9.   //  project.users という形で、アクセス可能  
  10.   //  また、キャッシュされるため、2度めのアクセスの際にはSQLは走らない  
  11.   // ##############################  
  12.   val userCache = collection.mutable.Map[Long, List[Product]]()  
  13.   def users(implicit session: Session) = {  
  14.     userCache.getOrElseUpdate(this.id, ProjectUserMap.users(this.id))  
  15.   }  
  16. }  
  17.   
  18. // define table schema  
  19. class Projects(tag: Tag) extends Table[Project](tag, "projects"with DAO{  
  20.   def id = column[Long]("id", O.PrimaryKey, O.AutoInc)  
  21.   def name = column[String]("name", O.NotNull)  
  22.   def description = column[String]("description", O.NotNull)  
  23.   def * = (id, name, description) <> (Project.tupled, Project.unapply)  
  24. }  
  25.   
  26. // define companion Object  
  27. object Projects extends DAO {  
  28.   def findById(id: Long)(implicit s: Session): Option[Project] = {  
  29.     Projects.filter { _.id === id }.firstOption  
  30.   }  
  31. }  
■ProjectUser.scala
  1. package models  
  2.   
  3. import java.sql.Timestamp  
  4. import models.Projects._  
  5. import play.api.db.slick.Config.driver.simple._  
  6.   
  7. // define dto  
  8. case class ProjectUser(user_id: Long, project_id: Long)  
  9.   
  10. // define table schema  
  11. class ProjectUserMap(tag: Tag) extends Table[ProjectUser](tag, "projects_users"with DAO{  
  12.   def user_id = column[Long]("user_id")  
  13.   def project_id = column[Long]("project_id")  
  14.   def * = (user_id, project_id) <> (ProjectUser.tupled, ProjectUser.unapply)  
  15.   def userFK = foreignKey("user2projectFK", user_id, Users)(u => u.id)  
  16.   def projectFK = foreignKey("project2userFK", project_id, Projects)(p => p.id)  
  17. }  
  18.   
  19.   
  20. // define companion Object  
  21. object ProjectUserMap extends DAO {  
  22.   def projects(user_id: Long)(implicit s: Session) = {  
  23.     ProjectUserMap.filter { _.user_id === user_id }.flatMap(_.projectFK).list  
  24.   }  
  25.   def users(project_id: Long)(implicit s: Session) = {  
  26.     ProjectUserMap.filter { _.project_id === project_id }.flatMap(_.userFK).list  
  27.   }  
  28. }  

↓以下、使い方
■Application.scala
  1. package controllers  
  2.   
  3. import models._  
  4. import play.api.mvc._  
  5. import play.api.db.slick._  
  6. import play.api.Play.current  
  7.   
  8.   
  9. object Application extends Controller{  
  10.   
  11.   def index = DBAction { implicit rc =>  
  12.     val user = Users.findById(1).get  
  13.     val projects = user.projects // SQL走る  
  14.     val projects2 = user.projects // ここでは、キャッシュされた結果が返るためSQLは走らない  
  15.     Ok("test")  
  16.   }  
  17.   
  18. }  

取得する列の指定など、拡張は今回は盛り込んでません!
ご指摘、などあればコメントお願い致します!!

Categories: ,

Leave a Reply