如何确保使用Table Per Subclass时的数据完整性? [英] How to ensure data integrity when using Table Per Subclass?

查看:171
本文介绍了如何确保使用Table Per Subclass时的数据完整性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过设置静态映射的 tablePerHierarchy 属性,我在Grails中使用 table per subclass code>字段在我的超类为false。这样,Grails为我的超类创建一个表,为每个子类创建一个附加表。

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






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

  class Product {
String productCode

static mapping = {
tablePerHierarchy false


以下的领域类作为子类:

  class Book延伸产品{
String isbn
}

结果创建了两个表, Product 表和 Book 表。例如,在创建一个通过脚手架的页面时,每个表格中都会插入一条记录,其唯一的链接就是ID值相同。具体而言,数据可能如下所示:

 产品
Id版本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; 

导入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扩展GrailsAnnotationConfiguration {

private static final long serialVersionUID = 1;

private boolean alreadyProcessed = false;

@Override
保护无效secondPassCompile()抛出MappingException {
super.secondPassCompile();

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




if(rootClass.hasSubclasses()){
Iterator子类= rootClass.getSubclassIterator();

while(subclasses.hasNext()){

Object subclass = subclasses.next();

//这个测​​试可以确保只有为
//使用table per subclass映射的子类才能创建外键
if(JoinedSubclass的子类instanceof){
JoinedSubclass joinedSubclass =(JoinedSubclass)子类;
joinedSubclass.createForeignKey();
}
}
}
}
}

alreadyProcessed = true;




$ b $ p $然后在 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以解决此问题。修复包括在Grails 2.3.8或2.3.9(不记得哪个)。

I am using the table per subclass strategy in Grails by setting the tablePerHierarchy property of the static mapping field in my superclass to false. This way, Grails creates one table for my superclass and one additional table for each of my subclasses.

However, while the superclass and subclass records share the same ID (primary key), there are no foreign key constraints to keep them consistent, i.e. it is possible to delete the superclass record, leaving the subclass record in an invalid state. I want to know if there is a setting/property to make GORM address this in some way, e.g. through constraints. Or is my only option to add foreign keys manually?


For example, given the following domain class as superclass:

class Product {
    String productCode

    static mapping = {
        tablePerHierarchy false
    }
}

And the following domain class as subclass:

class Book extends Product {
    String isbn
}

This results in the creation of two tables, the Product table and the Book table. When creating a Book – through scaffolded pages, for instance – a record is inserted into each table, their only link being the fact that the ID value is the same for each. Specifically, the data might look like this:

PRODUCT
Id      Version     ProductCode
1       1           BLAH-02X1

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

Because there is no formal relationship defined at the database level for these tables, it is possible to delete one of the records and leave the other, which results in invalid data. Obviously I can use SQL to manually create a foreign key constraint on the two ID fields, but I was hoping to let Grails handle that. Is this possible?


Using Grails 2.2.1

解决方案

Solved!

The following solution fixed this issue for me. Add the class below to src/java (this class cannot be written in 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;
    }
}

Then in DataSource.groovy set this as the configuration class

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"
}

Update

I've submitted a pull request to Grails for this issue. The fix was included in Grails 2.3.8 or 2.3.9 (can't remember which).

这篇关于如何确保使用Table Per Subclass时的数据完整性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆