Грааль много ко многим отношениям миграции - PullRequest
0 голосов
/ 12 июля 2011

Здравствуйте, у меня есть два класса домена, как показано ниже

class Users {

    String password
    String firstName
    String lastName
    String emailAddress
    String username
    Company company
.....
    static hasMany = [projects:Projects];
}

Другой класс

class Projects {
    String projectName
    String description
    Users projectLead
    Date dateCreated
    Date lastUpdated
    static belongsTo = Users
}

Эти классы, очевидно, имеют отношение один ко многим, но теперь я хочу изменить его на многие ко многимотношения, добавив класс "ProjectMembership", но у меня проблема в том, что мое приложение уже запущено в производство, и есть люди, которые уже используют приложение.В таком случае у них уже есть один пользователь-> много проектов в БД.В таком случае, как я могу перенести эти существующие данные и изменить мое приложение prod, чтобы иметь отношение m2m, которое будет выглядеть следующим образом.

class Users {

    String password
    String firstName
    String lastName
    String emailAddress
    String username
    Company company
.....
    static hasMany = [projectMemberships:ProjectMemberships];
}

Другой класс

class Projects {
    String projectName
    String description
    Users projectLead
    Date dateCreated
    Date lastUpdated
    static hasMany = [projectMemberships:ProjectMemberships];
}

и

class ProjectMemberships{
    Users u
    Projects p
}

1 Ответ

2 голосов
/ 12 июля 2011

Лучше всего это сделать с помощью инструмента миграции, такого как Liquibase, и плагин http://grails.org/plugin/database-migration, вероятно, лучше всего подходит для Grails, поскольку он использует Liquibase и тесно интегрирован с GORM.Но это достаточно легко сделать вручную.

Я бы не стал использовать hasMany, поскольку вы можете легко управлять всем из класса ProjectMemberships, поэтому ваши классы Users и Projects будут

class Users {
   String password
   String firstName
   String lastName
   String emailAddress
   String username
   Company company
.....
}

и

class Projects {
   String projectName
   String description
   Date dateCreated
   Date lastUpdated
}

Я бы пошел с классом ProjectMemberships, который использует составной ключ, который требует, чтобы он реализовал Serializable и имел хорошие hashCode иequals:

import org.apache.commons.lang.builder.HashCodeBuilder

class ProjectMemberships implements Serializable {
   Users u
   Projects p

   boolean equals(other) {
      if (!(other instanceof ProjectMemberships)) {
         return false
      }

      other.u?.id == u?.id && other.p?.id == p?.id
   }

   int hashCode() {
      def builder = new HashCodeBuilder()
      if (u) builder.append(u.id)
      if (p) builder.append(p.id)
      builder.toHashCode()
   }

   static ProjectMemberships get(long userId, long projectId) {
      find 'from ProjectMemberships where u.id=:userId and p.id=:projectId',
         [userId: userId, projectId: projectId]
   }

   static ProjectMemberships create(Users u, Projects p, boolean flush = false) {
      new ProjectMemberships(u: u, p: p).save(flush: flush, insert: true)
   }

   static boolean remove(Users u, Projects p, boolean flush = false) {
      ProjectMemberships instance = ProjectMemberships.findByUsersAndProjects(u, p)
      if (!instance) {
         return false
      }

      instance.delete(flush: flush)
      true
   }

   static void removeAll(Users u) {
      executeUpdate 'DELETE FROM ProjectMemberships WHERE u=:u', [u: u]
   }

   static void removeAll(Projects p) {
      executeUpdate 'DELETE FROM ProjectMemberships WHERE p=:p', [p: p]
   }

   static mapping = {
      id composite: ['p', 'u']
      version false
   }
}

Используйте ProjectMemberships.create(), чтобы добавить отношение между пользователем и проектом, и ProjectMemberships.remove(), чтобы удалить его.

Запустите grails schema-export, чтобы увидеть обновленный DDL (он будет в target/ddl.sql).Запустите оператор create table для таблицы project_memberships, например,

create table project_memberships (
   p_id bigint not null,
   u_id bigint not null,
   primary key (p_id, u_id)
)

Затем заполните его этим SQL-кодом (в зависимости от вашей базы данных вам может потребоваться немного другой синтаксис):

insert into project_memberships(p_id, u_id) select id, project_lead_id from projects

и, наконец, удалите столбец project_lead_id из таблицы projects.

Конечно, сделайте резервную копию базы данных перед внесением каких-либо изменений.

Вы можете получить проекты пользователя с помощью

def projects = ProjectMemberships.findAllByUsers(user)*.p

и аналогичные пользователи проекта с

def users = ProjectMemberships.findAllByProjects(project)*.u
...