grails - 使用 Table Per Subclass 时如何保证数据完整性?

标签 grails inheritance foreign-keys grails-orm table-per-class

我正在使用 每个子类的表 Grails 中的策略,通过设置 tablePerHierarchy静态属性 mapping我的父类(super class)中的字段为 false。这样,Grails 会为我的父类(super class)创建一张表,并为我的每个子类创建一张额外的表。

然而,虽然父类(super class)和子类记录共享相同的 ID(主键),但没有外键约束来保持它们的一致性,即可以删除父类(super class)记录,使子类记录处于无效状态。我想知道是否有设置/属性可以让 GORM 以某种方式解决这个问题,例如通过约束。或者是我手动添加外键的唯一选择?

例如,给定以下域类作为父类(super class):

class Product {
    String productCode

    static mapping = {
        tablePerHierarchy false
    }
}

并将以下域类作为子类:
class Book extends Product {
    String isbn
}

这导致创建两个表,Product表和Book table 。当创建一本书时——例如通过脚手架页面——将一条记录插入到每个表中,它们唯一的链接是每个表的 ID 值相同。具体来说,数据可能如下所示:
PRODUCT
Id      Version     ProductCode
1       1           BLAH-02X1

BOOK
Id      ISBN
1       123-4-56-7891011-1

因为这些表在数据库级别没有定义正式的关系,所以有可能删除其中一条记录而保留另一条记录,从而导致数据无效。显然我可以使用 SQL 在两个 ID 字段上手动创建外键约束,但我希望让 Grails 处理它。这可能吗?

使用 Grails 2.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"
}

更新

我已经提交了 pull request到 Grails 解决这个问题。该修复程序包含在 Grails 2.3.8 或 2.3.9 中(不记得是哪个)。

关于grails - 使用 Table Per Subclass 时如何保证数据完整性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16686322/

相关文章:

grails - Grails 中的自定义日志级别

grails - 为什么Grails的cookieService.get总是返回null?

grails - 基于日期的Grails查询

python - 继承虚拟类方法 - 如何从基类调用它?

c# - 重写继承方法时避免显式类型转换

c++ - 使用枚举编译时多态性

ruby-on-rails - 使用 Rails Minitest,测试如何通过但在重新测试时失败?

Grails 插件依赖项

python - SQLAlchemy 外键找不到表

java - Hibernate - 当在另一个类中进行自引用时处理添加(插入)