在Play 2中生成演化和模型的正确方法是什么?

时间:2013-07-19 18:57:48

标签: playframework-2.1 anorm

我知道evolution会在开发模式下自动应用。我的问题是,我如何产生变革?我如何生成与它们对应的模型?我目前面临很多打字输入一个简单的模型。它不是DRY,而且有很多样板。这似乎与Play文化背道而驰。

以下是我打字时遇到的代码,有什么更好的方式?:

1.SQL:     #---第一个数据库模式

# --- !Ups

create table task (
  id                        bigint not null primary key,
  title                     varchar(255) not null,
  done                      boolean,
  due_date                  timestamp,
  assigned_to               varchar(255),
  project                   bigint not null,
  folder                    varchar(255),
  foreign key(assigned_to)  references user(email) on delete set null,
  foreign key(project)      references project(id) on delete cascade
);

# --- !Downs

drop table if exists task;

Task.scala:

package models

import java.util.{Date}

import play.api.db._
import play.api.Play.current

import anorm._
import anorm.SqlParser._

case class Task(id: Pk[Long], folder: String, project: Long, title: String, done: Boolean, dueDate: Option[Date], assignedTo: Option[String])

object Task {

  // -- Parsers

  /**
   * Parse a Task from a ResultSet
   */
  val simple = {
    get[Pk[Long]]("task.id") ~
    get[String]("task.folder") ~
    get[Long]("task.project") ~
    get[String]("task.title") ~
    get[Boolean]("task.done") ~
    get[Option[Date]]("task.due_date") ~
    get[Option[String]]("task.assigned_to") map {
      case id~folder~project~title~done~dueDate~assignedTo => Task(
        id, folder, project, title, done, dueDate, assignedTo
      )
    }
  }

  // -- Queries

  /**
   * Retrieve a Task from the id.
   */
  def findById(id: Long): Option[Task] = {
    DB.withConnection { implicit connection =>
      SQL("select * from task where id = {id}").on(
        'id -> id
      ).as(Task.simple.singleOpt)
    }
  }

  /**
   * Retrieve todo tasks for the user.
   */
  def findTodoInvolving(user: String): Seq[(Task,Project)] = {
    DB.withConnection { implicit connection =>
      SQL(
        """
          select * from task 
          join project_member on project_member.project_id = task.project 
          join project on project.id = project_member.project_id
          where task.done = false and project_member.user_email = {email}
        """
      ).on(
        'email -> user
      ).as(Task.simple ~ Project.simple map {
        case task~project => task -> project
      } *)
    }
  }

  /**
   * Find tasks related to a project
   */
  def findByProject(project: Long): Seq[Task] = {
    DB.withConnection { implicit connection =>
      SQL(
        """
          select * from task 
          where task.project = {project}
        """
      ).on(
        'project -> project
      ).as(Task.simple *)
    }
  }

  /**
   * Delete a task
   */
  def delete(id: Long) {
    DB.withConnection { implicit connection =>
      SQL("delete from task where id = {id}").on(
        'id -> id
      ).executeUpdate()
    }
  }

  /**
   * Delete all task in a folder.
   */
  def deleteInFolder(projectId: Long, folder: String) {
    DB.withConnection { implicit connection =>
      SQL("delete from task where project = {project} and folder = {folder}").on(
        'project -> projectId, 'folder -> folder
      ).executeUpdate()
    }
  }

  /**
   * Mark a task as done or not
   */
  def markAsDone(taskId: Long, done: Boolean) {
    DB.withConnection { implicit connection =>
      SQL("update task set done = {done} where id = {id}").on(
        'id -> taskId,
        'done -> done
      ).executeUpdate()
    }
  }

  /**
   * Rename a folder.
   */
  def renameFolder(projectId: Long, folder: String, newName: String) {
    DB.withConnection { implicit connection =>
      SQL("update task set folder = {newName} where folder = {name} and project = {project}").on(
        'project -> projectId, 'name -> folder, 'newName -> newName
      ).executeUpdate()
    }
  }

  /**
   * Check if a user is the owner of this task
   */
  def isOwner(task: Long, user: String): Boolean = {
    DB.withConnection { implicit connection =>
      SQL(
        """
          select count(task.id) = 1 from task 
          join project on task.project = project.id 
          join project_member on project_member.project_id = project.id 
          where project_member.user_email = {email} and task.id = {task}
        """
      ).on(
        'task -> task,
        'email -> user
      ).as(scalar[Boolean].single)
    }
  }

  /**
   * Create a Task.
   */
  def create(task: Task): Task = {
    DB.withConnection { implicit connection =>

      // Get the task id
      val id: Long = task.id.getOrElse {
        SQL("select next value for task_seq").as(scalar[Long].single)
      }

      SQL(
        """
          insert into task values (
            {id}, {title}, {done}, {dueDate}, {assignedTo}, {project}, {folder}
          )
        """
      ).on(
        'id -> id,
        'folder -> task.folder,
        'project -> task.project,
        'title -> task.title,
        'done -> task.done,
        'dueDate -> task.dueDate,
        'assignedTo -> task.assignedTo
      ).executeUpdate()

      task.copy(id = Id(id))

    }
  }

}

2 个答案:

答案 0 :(得分:2)

Ebean本身不支持DDL更改,因此使用自动演进只能从头开始创建第一个DDL。

接下来的演变,你需要(字面意思)自己编写,包含所有UP和DOWN,因此在开始时规划初始DDL是非常重要的一步。

危险:正如您可能已经意识到自动创建的'scratch-evoulution'也会执行之前DDL的DOWN,这意味着您的所有数据都将丢失。

答案 1 :(得分:0)

你的问题有两部分 - 演变和Scala模型。对于演进,大多数DB都有工具为你生成大部分SQL代码(例如mysql工作台中的“前向工程师”等),有些会生成diff(alter / update)语句(例如mysql workbench的{{3})这使得创造变革变得更容易。

对于Scala模型,您可以查看Synchronize Model。我已经根据自己的标准调整了模板/等等,它们肯定会提供一个先机。