如何确保使用Table Per Subclass时的数据完整性? [英] How to ensure data integrity when using 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屋!