我知道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))
}
}
}
答案 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。我已经根据自己的标准调整了模板/等等,它们肯定会提供一个先机。