2009-11-12 4 views
5

Grailles GORM ne conserve pas les classes de domaine abstraites dans la base de données, provoquant une rupture des relations polymorphes. Par exemple:Classes abstraites dans les relations 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) 
    } 
} 

provoque

Causée par: org.hibernate.MappingException: Une association du document de table fait référence à une classe unmapped: User ... 25 plus 2009-11- 11 23: 52: 58,933 [principal] ERREUR mortbay.log - imbriqué dans org.springframework.beans.factory.BeanCreationException: Erreur lors de la création du bean avec le nom 'messageSource': L'initialisation du bean a échoué; l'exception imbriquée est org.springframework.beans.factory.BeanCreationException: erreur création d'un bean avec le nom 'transactionManager': impossible de résoudre la référence en bean 'sessionFactory' lors de la définition de la propriété bean 'sessionFactory'; l'exception imbriquée est org.springframework.beans.factory.BeanCreationException: erreur création d'un bean avec le nom 'sessionFactory': l'appel de la méthode init a échoué; exception imbriquée est org.hibernate.MappingException: Une association du document de tableau fait référence à une classe non cartographiées: Utilisateur: org.hibernate.MappingException: Une association du document de table fait référence à une classe unmapped: User

Mais dans ce scénario, je veux les effets polymorphiques de permettre à tout utilisateur de posséder un document, tout en forçant chaque utilisateur du système à s'intégrer dans l'un des rôles définis. Par conséquent, l'utilisateur ne doit pas être directement instancié et est rendu abstrait. Je ne veux pas utiliser une énumération pour les rôles dans une classe User non abstraite, car je veux pouvoir ajouter des propriétés supplémentaires aux différents rôles, ce qui peut ne pas avoir de sens dans certains contextes (I do ' Je veux avoir un seul utilisateur avec un rôle défini sur RegularEmployee qui obtient en quelque sorte un managedGroup non nul).

Est-ce un bug dans Grails? Est-ce que je manque quelque chose?

+0

Je me demande ce que cela signifierait pour qu'une classe abstraite soit conservée dans la base de données, car il doit y avoir quelque chose à persister (c'est-à-dire, une instance). –

+0

Eh bien, je dirais qu'une classe abstraite est le schéma préliminaire du schéma, surtout si c'est à la racine d'une relation d'héritage. Donc, si j'ai une relation Utilisateur-> RegularEmployee, le nom de la table doit être User et une colonne doit être ajoutée pour "class", qui est utilisée pour stocker le type dans le modèle standard de table par hiérarchie. –

Répondre

3

Vous aimeriez voir les modèles de domaines pour les plugins Shiro, Nimble (utilise Shiro) et/ou Spring Security. Ils créent un domaine utilisateur concret et un domaine de rôle concret. Shiro crée en particulier un domaine UserRole pour le mappage many-to-many. Ensuite, sur votre domaine Role, vous pouvez ajouter les propriétés souhaitées. Si nécessaire, vous pouvez créer un domaine distinct pour permettre des propriétés arbitraires comme ceci:

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

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

Je ne pense pas que vous obtiendrez ce que vous cherchez dans votre cartographie de domaine actuel bien.

+0

Super appel sur les plug-ins Shiro, Nimble et Spring Security (je suppose que c'est Acegi?). Je suis à la recherche d'une comparaison entre eux, mais tout ce que je trouve, ce sont les anciens messages sur les listes de diffusion de 2K7, qui ont probablement une applicabilité limitée aux Grails modernes. Connaissez-vous des ressources qui offrent des comparaisons côte à côte? –

+0

Non, je n'ai jamais trouvé une comparaison approfondie sur eux tous. J'ai utilisé Shiro auparavant (en tant que JSecurity) donc quand Nimble a été annoncé plus tôt cette année, cela semblait être un mouvement naturel (basé sur Shiro avec un ensemble de fonctionnalités bien plus important). J'ai seulement vu des articles sur Spring Security (aka Acegi) mais je n'en ai jamais lu plus à ce sujet. –

2

Nous testons l'héraldique héréditaire du graal l'autre jour au travail pour observer le polymorphisme. Nous avons trouvé les scénarios suivants:

Résumé Superclasse - Les sous-classes héritent du comportement du parent mais le parent ne peut pas être utilisé pour référencer une sous-classe que vous souhaitez stocker dans la base de données.

Superclasse avec tablePerHeirarchy false - Les sous-classes stockent les champs du parent dans la table du parent, le polymorphisme fonctionne comme prévu.

Empty Superclass avec tablePerHeirarchy false - Les sous-classes stockent toutes leurs propres données dans leur table, le polymorphisme fonctionne comme prévu. Donc, dans votre cas, si vous faites supprimer le mot-clé abstract de la classe d'utilisateurs, tout fonctionnera comme prévu. Le seul inconvénient est que tous les champs User sont stockés dans la table User, laissant la table RegularEmployee avec uniquement les colonnes id et version et la table Manager n'ayant qu'une référence à une ligne Workgroup.

+0

Intéressant, mais supprimer le mot-clé abstract permettrait également l'instanciation des objets User. Cela signifie qu'il existe un moyen de créer un utilisateur qui n'est pas explicitement forcé dans l'un des rôles, ce qui viole ma logique métier. –

+0

C'est un bon point. Je suppose que vous pourriez contourner cela en créant un constructeur explicite qui lance une exception, mais même alors, ce que nous voulons vraiment, c'est une classe abstraite. Pour tous ceux qui lisent ceci, assurez-vous de voter pour le numéro sur JIRA. http://jira.codehaus.org/browse/GRAILS-5356 – Blacktiger

Questions connexes