2009-11-12 10 views
5

Grails GORM no persiste clases abstractas de dominio en la base de datos, lo que provoca una interrupción en las relaciones polimórficas. Por ejemplo:Clases abstractas en relaciones GORM

abstract class User { 
    String email 
    String password 
    static constraints = { 
     email(blank:false, nullable:false,email:true) 
     password(blank:false, password:true) 
    } 

    static hasMany = [membership:GroupMembership] 
} 

class RegularEmployee extends User {} 

class Manager extends User { 
    Workgroup managedGroup 
} 

class Document { 
    String name 
    String description 
    int fileSize 
    String fileExtension 
    User owner 
    Date creationTime 
    Date lastModifiedTime 
    DocumentData myData 
    boolean isCheckedOut 
    enum Sensitivity {LOW,MEDIUM,HIGH} 
    def documentImportance = Sensitivity.LOW 

    static constraints = { 
     name(nullable:false, blank:false) 
     description(nullable:false, blank:false) 
     fileSize(nullable:false) 
     fileExtension(nullable:false) 
     owner(nullable:false) 
     myData(nullable:false) 
    } 
} 

provoca

causada por: org.hibernate.MappingException: Una asociación a partir del documento tabla se refiere a una clase de unmapped: User ... 25 más 2009-11- 11 23: 52: 58,933 [main] ERROR mortbay.log - Anidado en org.springframework.beans.factory.BeanCreationException: error al crear bean con el nombre 'messageSource': Inicialización del bean falló; la excepción anidada es org.springframework.beans.factory.BeanCreationException: Error creando bean con el nombre 'transactionManager': No se puede resolver la referencia para bean 'sessionFactory' mientras se configura la propiedad bean 'sessionFactory'; excepción anidada es org.springframework.beans.factory.BeanCreationException: Error creando bean con el nombre 'sessionFactory': Invocación del método init failed; excepción anidada es org.hibernate.MappingException: Un asociación del documento de tabla se refiere a una clase de unmapped: Usuario: org.hibernate.MappingException: Una asociación a partir del documento mesa se refiere a una clase de unmapped: User

Pero en este escenario, quiero los efectos polimórficos de permitir que cualquier usuario posea un documento, mientras forzo a cada usuario del sistema a encajar en una de las funciones definidas. Por lo tanto, el usuario no debe ser instanciado directamente y se hace abstracto.

No quiero usar una enumeración de roles en una clase de usuario no abstracta, porque quiero poder agregar propiedades adicionales a los diferentes roles, lo que puede no tener sentido en ciertos contextos (no lo hago) t quiero tener un usuario único con la función establecida en RegularEmployee que de alguna manera obtenga un grupo administrado no nulo).

¿Esto es un error en Grails? ¿Me estoy perdiendo de algo?

+0

Me pregunto qué significaría que una clase abstracta persista en el DB, ya que tiene que haber algo para persistir (es decir, una instancia). –

+0

Bueno, me atrevo a aventurar que una clase abstracta es el esquema del esquema preliminar, especialmente si está en la raíz de una relación de herencia. Entonces, si tengo una relación Usuario-> EmpleadoEmpleo, el nombre de la tabla debe ser Usuario y se debe agregar una columna para "clase", que se usa para almacenar el tipo al estilo del modelo estándar de tabla por jerarquía. –

Respuesta

3

Puede que desee ver los modelos de dominio para los complementos de Shiro, Nimble (usa Shiro) y/o Spring Security. Crean un dominio de Usuario concreto y un dominio de Rol concreto. Shiro, en particular, crea un dominio UserRole para la asignación de muchos a muchos.

Luego, en su dominio de rol, puede agregar las propiedades que desee. Si es necesario, puede crear un dominio específico que recoja las propiedades arbitrarias, así:

class Role { 
    //some properties 
    static hasMany = [roleProperties:RoleProperty, ...] 
} 

class RoleProperty { 
    String name 
    String value 
    static belongsTo = [role:Role] 
} 

no creo que obtendrá lo que estás buscando en su dominio de la cartografía actual sin embargo.

+0

Gran convocatoria para los complementos Shiro, Nimble y Spring Security (¿supongo que esto es Acegi?). Estoy buscando una comparación entre ellos, pero todo lo que encuentro son publicaciones antiguas en listas de correo de 2K7, que probablemente tienen una aplicabilidad limitada a los Grails modernos. ¿Conoces algún recurso que ofrezca comparaciones lado a lado? –

+0

No, nunca he encontrado una comparación extensa en todos ellos. He usado a Shiro antes (como JSecurity) así que cuando se anunció a Nimble a principios de este año, parecía un movimiento natural (basado en Shiro con un conjunto de características mucho mayor). Solo he visto publicaciones sobre Spring Security (también conocido como Acegi) pero nunca leo más sobre esto. –

2

Estábamos probando la jerarquía de herencia de los griales el otro día en el trabajo para observar el polimorfismo. Encontramos los siguientes escenarios:

Resumen Superclase: las subclases heredan el comportamiento del elemento primario pero el elemento primario no se puede usar para hacer referencia a una subclase que desea almacenar en la base de datos.

Superclase con tablaPerHerarchy falso - Las subclases almacenan los campos principales en la tabla primaria, el polimorfismo funciona como se esperaba.

Empty Superclass with tablePerHeirarchy false - Las subclases almacenan todos sus datos en su tabla, el polimorfismo funciona como se esperaba.

En su caso, si fuera a eliminar la palabra clave abstracta de la clase de usuario, todo funcionaría como se esperaba. El único inconveniente es que todos los campos de Usuario se almacenan en la tabla de Usuario, dejando la tabla de Empleado Regular con solo las columnas de Id. Y Versión y la tabla de Administrador teniendo solo una referencia a una fila de Grupo de Trabajo.

+0

Interesante, pero eliminar la palabra clave abstracta también permitiría la creación de instancias de los objetos del Usuario. Esto significa que hay una manera de crear un usuario que no esté explícitamente forzado en uno de los roles, lo que viola mi lógica comercial. –

+0

Ese es un buen punto. Supongo que podrías solucionarlo creando un constructor explícito que arroje una excepción, pero incluso entonces lo que realmente queremos es una clase abstracta. Para cualquier otra persona que lea esto, asegúrese de votar por el tema en JIRA. http://jira.codehaus.org/browse/GRAILS-5356 – Blacktiger

Cuestiones relacionadas