2009-11-12 9 views
5

Grails GORM speichert keine abstrakten Domänenklassen in der Datenbank, was zu einem Bruch der polymorphen Beziehungen führt. Zum Beispiel:Abstrakte Klassen in GORM-Beziehungen

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

verursacht

Verursacht durch: org.hibernate.MappingException: Ein Verein aus dem Tabelle Dokument bezieht sich auf eine nicht zugeordneten Klasse: User ... 25 weitere 2009-11- 11 23: 52: 58.933 [main] FEHLER mortbay.log - Verschachtelt in org.springframework.beans.factory.BeanCreationException: Fehler beim Erstellen der Bean mit dem Namen 'messageSource': Initialisierung der Bean fehlgeschlagen; Verschachtelte Ausnahme ist org.springframework.beans.factory.BeanCreationException: Fehler Erstellen Bean mit Name 'transactionManager': Kann Referenz zu Bean 'SessionFactory' nicht aufgelöst werden beim Festlegen der Bean Eigenschaft 'sessionFactory'; verschachtelte Ausnahme ist org.springframework.beans.factory.BeanCreationException: Fehler Erstellen von Bean mit Name 'SessionFactory': Aufruf der Init-Methode fehlgeschlagen; nested Ausnahme ist org.hibernate.MappingException: Eine Vereinigung aus der Tabelle Dokument an eine nicht zugeordnete Klasse bezieht: User: org.hibernate.MappingException: Eine Vereinigung aus der Tabelle Dokument zu einer nicht zugeordneten Klasse verweist: User

Aber in diesem Szenario möchte ich die polymorphen Auswirkungen, die es jedem Benutzer erlauben, ein Dokument zu besitzen, während jeder Benutzer des Systems gezwungen wird, in eine der definierten Rollen zu passen. Daher sollte der Benutzer nicht direkt instanziiert und abstrakt gemacht werden.

Ich möchte keine Aufzählung für Rollen in einer nicht abstrakten Benutzerklasse verwenden, weil ich in der Lage sein möchte, den verschiedenen Rollen zusätzliche Eigenschaften hinzuzufügen, die in bestimmten Kontexten keinen Sinn ergeben (I don ' t möchte einen einzelnen Benutzer haben, dessen Rolle auf RegularEmployee gesetzt ist, der irgendwie eine nicht-null-managedGroup erhält).

Ist das ein Fehler in Grails? Fehle ich etwas?

+0

Ich frage mich, was es bedeuten würde für eine abstrakte Klasse in der DB beibehalten werden, da es etwas geben muss (d. H. Eine Instanz). –

+0

Nun, ich würde wagen, dass eine abstrakte Klasse ist die vorläufige Schema-Gliederung, vor allem wenn es als die Wurzel einer Vererbungsbeziehung. Wenn ich also eine Benutzer-> RegularEmployee-Beziehung habe, sollte der Tabellenname Benutzer sein und eine Spalte für "Klasse" hinzugefügt werden, die zum Speichern des Typs nach dem Standardmodell für jede Tabelle verwendet wird. –

Antwort

3

Sie mögen vielleicht die Domänenmodelle für die Shiro, Nimble (verwendet Shiro) und/oder Spring Security-Plugins anzuzeigen. Sie erstellen eine konkrete Benutzerdomäne und eine konkrete Rollendomäne. Shiro erstellt insbesondere eine UserRole-Domäne für das Viele-zu-Viele-Mapping.

Dann auf Ihrer Rolle Domain, können Sie, was Sie wollen Eigenschaften hinzufügen. Falls erforderlich, können Sie eine separate Domäne erstellen, wie so für beliebige Eigenschaften ermöglichen:

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

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

Ich glaube nicht, Sie bekommen, was Sie suchen in Ihrem obwohl aktuellen Domain-Mapping.

+0

Toller Anruf bei den Shiro, Nimble und Spring Security Plugins (ich nehme an, das ist Acegi?). Ich suche nach einem Vergleich zwischen ihnen, aber alles, was ich finde, sind alte Einträge in Mailinglisten von 2K7, die wahrscheinlich nur begrenzt auf moderne Grails anwendbar sind. Kennst du zufällig irgendwelche Ressourcen, die Seite-an-Seite-Vergleiche anbieten? –

+0

Nein, ich habe nie einen ausführlichen Vergleich zu allen gefunden. Ich habe Shiro schon früher benutzt (als JSecurity) und als Nimble Anfang dieses Jahres angekündigt wurde, schien es ein natürlicher Zug zu sein (basierend auf Shiro mit einem viel größeren Feature-Set). Ich habe immer nur Beiträge über Spring Security (aka Acegi) gesehen, aber habe nie mehr darüber gelesen. –

2

Wir waren testet die Hierarchie grails Erbschaft den anderen Tag bei der Arbeit an Polymorphismus zu suchen. Wir haben die folgenden Szenarien gefunden:

Abstract Superklasse - Unterklassen erben das Verhalten des übergeordneten Elements, aber das übergeordnete Element kann nicht verwendet werden, um auf eine Unterklasse zu verweisen, die in der Datenbank gespeichert werden soll.

Superklasse mit tablePerHeirarchy false - Subklassen die Felder des Mutter speichern in der Tabelle der Eltern, arbeitet Polymorphismus wie erwartet.

Leere Oberklasse mit tablePerHeirarchy false - Unterklassen speichern alle ihre eigenen Daten in ihrer Tabelle, Polymorphismus funktioniert wie erwartet.

Also in Ihrem Fall, wenn Sie das abstrakte Schlüsselwort aus der Benutzerklasse entfernen würden, würde alles wie erwartet funktionieren. Der einzige Nachteil ist, dass alle User-Felder in der User-Tabelle gespeichert sind und die RegularEmployee-Tabelle nur die ID- und Versionsspalten und die Manager-Tabelle nur einen Verweis auf eine Workgroup-Zeile enthält.

+0

Interessant, aber das Entfernen des abstrakten Schlüsselworts würde auch die Instanziierung von Benutzerobjekten ermöglichen. Dies bedeutet, dass es eine Möglichkeit gibt, einen Benutzer zu erstellen, der nicht explizit in eine der Rollen gezwungen wird, was gegen meine Geschäftslogik verstößt. –

+0

Das ist ein guter Punkt. Ich nehme an, Sie könnten das umgehen, indem Sie einen expliziten Konstruktor erstellen, der eine Ausnahme auslöst, aber selbst dann wollen wir eigentlich eine abstrakte Klasse. Für jeden, der dies liest, sollten Sie auf JIRA abstimmen. http://jira.codehaus.org/browse/GRAILS-5356 – Blacktiger

Verwandte Themen