Grails域模型中的继承

时间:2014-01-31 17:14:42

标签: grails gorm

我的Grails应用程序的域模型具有以下要求:

  • 用户属于零个或一个组织
  • 组织是慈善机构或公司
  • 慈善机构和公司有一些共同的领域,还有一些(非可空)领域,这些领域对每种组织类型都是唯一的

我将公共组织字段放入一个抽象的Organisation类中,CharityCompany都扩展。我无法将此层次结构存储在单个表中,因为存在特定于每种组织类型的非可空字段。域模型的相关部分如下所示:

class User {
  String name

  static belongsTo = [organization: Organization]

  static constraints = {
    organization nullable: true
  }
}

abstract class Organization {    
    String name

    static hasMany = [users: User]

    static mapping = {
        tablePerHierarchy false
    }
}

class Charity extends Organization {
  // charity-specific fields go here
} 

class Company extends Organization {
  // company-specific fields go here
}

当我查看从该模型生成的MySQL模式时,组织公司和组织慈善机构之间的继承关系似乎已被完全忽略。虽然有一个带有名称列的组织表,但它与公司或慈善机构没有主要 - 外键关系

3 个答案:

答案 0 :(得分:2)

  1. 对于MySQL和H2,我看到与IanRoberts相同的结果。换句话说:没有生成连接表,但organization_id表中的预期users FK。
  2. 使用"每个子类的表"映射(tablePerHierarchy false),您最终会在数据库中隐含一对一的关系。 CharityCompany的主键值与父Organization的PK值相同。 GORM / Hibernate3生成的模式似乎没有使用参照完整性约束来强制执行此模式。它是纯粹的Hibernate魔法。更详细一点here

答案 1 :(得分:1)

ORM不是RDBS。

  1.   

    tablePerHierarchy false

  2. 所以你有三张桌子:组织,慈善,公司。用户仅属于组织(不是慈善机构或公司)。你如何获得特定领域的价值? 有USER。我们了解组织,但我们不了解慈善机构或公司。我想你了......

    我可以向您推荐三种解决方案:

    1。 tablePerHierarchy为true(但您需要拥有可以为空的慈善机构\公司特定字段)

    <强> 2

    class User {
        static belongsTo = [charity: Charity, company: Company]
    }
    
    
    class Charity {
        String name
        static hasMany = [users: User]
        // charity-specific fields go here
    }
    
    class Company {
        String name
        static hasMany = [users: User]
        // company-specific fields go here
    }  
    

    第3

    class User {
        static belongsTo = [organization: Organization]
    }
    
    class Organization {    
        String name
        Charity charity //nullable
        Company company //nullable
        static hasMany = [users: User]
    }
    
    class Charity {
        static belongsTo = [organization: Organization]
        // charity-specific fields go here
    }
    
    class Company {
        static belongsTo = [organization: Organization]
        // company-specific fields go here
    }  
    

答案 2 :(得分:1)

解决!

将下面的类添加到src/java(此类不能用Groovy编写)

package org.example;

import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration;
import org.hibernate.MappingException;
import org.hibernate.mapping.JoinedSubclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;

import java.util.Iterator;

public class TablePerSubclassConfiguration extends GrailsAnnotationConfiguration {

    private static final long serialVersionUID = 1;

    private boolean alreadyProcessed = false;

    @Override
    protected void secondPassCompile() throws MappingException {
        super.secondPassCompile();

        if (alreadyProcessed) {
            return;
        }

        for (PersistentClass persistentClass : classes.values()) {
            if (persistentClass instanceof RootClass) {
                RootClass rootClass = (RootClass) persistentClass;

                if (rootClass.hasSubclasses()) {
                    Iterator subclasses = rootClass.getSubclassIterator();

                    while (subclasses.hasNext()) {

                        Object subclass = subclasses.next();

                        // This test ensures that foreign keys will only be created for subclasses that are
                        // mapped using "table per subclass"
                        if (subclass instanceof JoinedSubclass) {
                            JoinedSubclass joinedSubclass = (JoinedSubclass) subclass;
                            joinedSubclass.createForeignKey();
                        }
                    }
                }
            }
        }

        alreadyProcessed = true;
    }
}

然后在DataSource.groovy中将其设置为配置类

dataSource {
    configClass = 'org.example.TablePerSubclassConfiguration'
    pooled = true
    driverClassName = "org.h2.Driver"
    username = "sa"
    password = ""
    dbCreate = "update"
    url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
}

我已经向Grails提交了pull request来解决此问题。该修复程序包含在Grails 2.3.9中。