2011-07-12 100 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