query outside grails inheritance foreign-keys gorm table-per-class

query - gorm outside grails



¿Cómo garantizar la integridad de los datos cuando se usa Table Per Subclass? (2)

Hibernate garantiza la integridad de los datos en el caso de la tabla por subclase. En el caso de la tabla por subclase, la subclase mantiene una asociación de clave primaria con la superclase. Eche un vistazo a Hibernate Table por subclase . Para validar el hecho, aquí está su caso de prueba:

class Product { String productCode static mapping = { tablePerHierarchy false } } class Book extends Product{ String isbn } //Test Case def testTablePerSubclass{ def product = new Product(productCode: ''XYZ456'') product.save(flush: true, failOnError: true) def book = new Book(isbn: ''123456123'', productCode: ''ABC123'') book.save(flush: true, failOnError: true) assert Book.list().size() == 1 //One Book assert Book.list()*.id == [2] //Book id assert Product.list().size() == 2 //One Product, one Book (2 Products) assert Product.list()*.id == [1, 2] //Product id, Book Id //Grab the product (book) to delete def productToDelete = Product.get(book.id) productToDelete.delete(flush: true) assert Book.list().isEmpty() //Book deleted from Book table as well assert Product.list().size() == 1 //One Product remaining in Product table assert Product.list()*.id == [1] //Remaining Product Id }

Mantenga logSql verdadero en DataSource.groovy para ver cómo se ejecutan los sqls correspondientes.

Log Sql Output:- Hibernate: insert into product (id, version, product_code) values (null, ?, ?) Hibernate: insert into product (id, version, product_code) values (null, ?, ?) Hibernate: insert into book (isbn, id) values (?, ?) Hibernate: select this_.id as id0_0_, this_1_.version as version0_0_, this_1_.product_code as product3_0_0_, this_.isbn as isbn1_0_ from book this_ inner join product this_1_ on this_.id=this_1_.id [com.example.Book : 2] Hibernate: select this_.id as id0_0_, this_.version as version0_0_, this_.product_code as product3_0_0_, this_1_.isbn as isbn1_0_, case when this_1_.id is not null then 1 when this_.id is not null then 0 end as clazz_0_ from product this_ left outer join book this_1_ on this_.id=this_1_.id [com.example.Product : 1, com.example.Book : 2] Hibernate: delete from book where id=? Hibernate: delete from product where id=? and version=? Hibernate: select this_.id as id0_0_, this_1_.version as version0_0_, this_1_.product_code as product3_0_0_, this_.isbn as isbn1_0_ from book this_ inner join product this_1_ on this_.id=this_1_.id [] Hibernate: select this_.id as id0_0_, this_.version as version0_0_, this_.product_code as product3_0_0_, this_1_.isbn as isbn1_0_, case when this_1_.id is not null then 1 when this_.id is not null then 0 end as clazz_0_ from product this_ left outer join book this_1_ on this_.id=this_1_.id [com.example.Product : 1]

Usando Grails 2.2.2

Estoy utilizando la tabla por estrategia de subclase en Grails estableciendo la propiedad tablePerHierarchy del campo de mapping estática en mi superclase en falso. De esta forma, Grails crea una tabla para mi superclase y una tabla adicional para cada una de mis subclases.

Sin embargo, aunque los registros de superclase y subclase comparten el mismo ID (clave principal), no hay restricciones de clave externa para mantenerlos constantes, es decir, es posible eliminar el registro de superclase, dejando el registro de subclase en un estado no válido. Quiero saber si hay una configuración / propiedad para hacer que GORM aborde esto de alguna manera, por ejemplo, mediante restricciones. ¿O es mi única opción agregar manualmente claves foráneas?

Por ejemplo, dada la siguiente clase de dominio como superclase:

class Product { String productCode static mapping = { tablePerHierarchy false } }

Y la siguiente clase de dominio como subclase:

class Book extends Product { String isbn }

Esto resulta en la creación de dos tablas, la tabla Product y la tabla Book . Al crear un libro, por ejemplo, a través de páginas con scaffolded, se inserta un registro en cada tabla, siendo su único vínculo el hecho de que el valor de ID sea el mismo para cada uno. Específicamente, los datos pueden verse así:

PRODUCT Id Version ProductCode 1 1 BLAH-02X1 BOOK Id ISBN 1 123-4-56-7891011-1

Debido a que no existe una relación formal definida en el nivel de la base de datos para estas tablas, es posible eliminar uno de los registros y dejar el otro, lo que da como resultado datos no válidos. Obviamente, puedo usar SQL para crear manualmente una restricción de clave externa en los dos campos de ID, pero esperaba dejar que Grails manejara eso. es posible?

Usando Grails 2.2.1


Resuelto

La siguiente solución me solucionó este problema. Agregue la clase a continuación a src/java (esta clase no se puede escribir en 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; } }

Luego en DataSource.groovy establece esto como la clase de configuración

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

Actualizar

He enviado una solicitud de extracción a Grails para este problema. La solución se incluyó en Grails 2.3.8 o 2.3.9 (no recuerdo cuál).