使用Table Per Subclass时如何确保数据完整性?

Ste*_*han 6 grails inheritance foreign-keys grails-orm table-per-class

通过将我的超类中的静态字段的属性设置为false,我在Grails中使用每个子类策略的.这样,Grails为我的超类创建了一个表,为每个子类创建了一个附加表.tablePerHierarchymapping

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


例如,给定以下域类作为超类:

class Product {
    String productCode

    static mapping = {
        tablePerHierarchy false
    }
}
Run Code Online (Sandbox Code Playgroud)

以下域类作为子类:

class Book extends Product {
    String isbn
}
Run Code Online (Sandbox Code Playgroud)

这导致创建两个表,即Product表和Book表.例如,当创建Book(通过脚手架页面)时,会在每个表中插入一条记录,它们唯一的链接就是每个表的ID值相同.具体来说,数据可能如下所示:

PRODUCT
Id      Version     ProductCode
1       1           BLAH-02X1

BOOK
Id      ISBN
1       123-4-56-7891011-1
Run Code Online (Sandbox Code Playgroud)

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


使用Grails 2.2.1

Dón*_*nal 4

解决了!

以下解决方案为我解决了这个问题。添加以下类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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将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"
}
Run Code Online (Sandbox Code Playgroud)

更新

我已针对此问题向 Grails提交了拉取请求。该修复包含在 Grails 2.3.8 或 2.3.9 中(不记得是哪个)。