2011-07-12 101 views
0

您好,我有两个域类如下Grails的多对多关系迁移

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”类到许多关系,但我遇到的问题是我的应用程序已经投入生产,并且有些人已经在使用该应用程序。在这种情况下,他们已经在db中拥有一个用户 - >多个项目。在这种情况下,我该如何迁移这些现有数据并更改我的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 
} 

回答

2

这最好用像Liquibase迁移工具来完成,而http://grails.org/plugin/database-migration插件可能是你最好是在Grails的,因为它使用Liquibase并与GORM紧密集成。但这个人很容易手工完成。

我不会用hasMany因为你可以很容易地从ProjectMemberships类管理一切,所以你UsersProjects类是

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并具有良好的hashCodeequals

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)。运行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 

终于从projects表中删除project_lead_id列。

当然在做任何改变之前做一个数据库备份。

你可以得到一个用户的项目

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

,同样一个项目的用户

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

不知何故,我知道,这将是你从他们那里我会得到一个答案。非常感谢。 – Sap