2016-10-03 3 views
0

Beim Migrieren einer vorhandenen App von Grails 2.5 auf 3.1 stieß ich auf ein seltsames Problem mit einer bidirektionalen Eins-zu-Eins-Beziehung.Grails 3 hasOne nullability-Problem

Stellen Sie sich ein einfaches Modell mit einem Benutzer und Employee Objekte vor. Ein User repräsentiert ein generisches Benutzerkonto. Nicht alle Benutzer sind Mitarbeiter, aber alle Mitarbeiter sind Benutzer. Darüber hinaus haben Mitarbeiter Referenzen auf Manager, Supervisor usw. (auch User-Instanzen). Benutzer ist die besitzende Seite der Beziehung.

class User { 
    Employee employee 

    static mappedBy = [employee: "user"] 
    static hasOne = [employee: Employee] 

    static constraints = { 
    employee(nullable:true) 
    } 
} 

class Employee { 
    User user // represents employee's own account, a bi-directional one-to-one 
    User supervisor // represents a supervisor 

    static belongsTo = [user: User] 

    static constraints = { 
    user(unique:true) 
    supervisor(nullable:true) 
    } 
} 

Das Problem nach dem Upgrade 3 bis Grails ist, dass der Modus erzeugen in diesem in supervisor_id Spalte von Tabelle employee als NOT NULL wobei ergibt erzeugt, wohingegen in Grails 2 es NULL festlegbaren wie erwartet war (nur mit NOT NULL user_id).

Ich habe dies mit Grails 3.1.12 und 3.2.0 getestet, das gleiche Verhalten mit beiden erhalten. Mache ich irgendetwas Dummes in meinen Domain-Klassen-Deklarationen? Ich habe mehrere Mappings ausprobiert, um ohne Glück dasselbe Verhalten wie in Grails 2.5 zu erreichen. In einigen Fällen bekomme ich sogar einen Fremdschlüssel auf beiden Seiten der Beziehung ...

Antwort

0

Ich weiß nicht, warum Ihr Code mit der vorherigen Version von Grails arbeitete, aber es ist falsch.

Wenn Sie hasMany und ansicesTo verwenden, müssen Sie keine andere Eigenschaft im untergeordneten Objekt definieren, und Sie müssen auch nicht die Eigenschaft mappedBy für das übergeordnete Element und dasselbe für das übergeordnete Element (Eigenschaft employee at Benutzer)

Grails braucht nichts anderes zu wissen, welche die bidirektionale Eigenschaft auf beiden Klassen ist, und die Contraint user(unique : true) weder.

So Ihre Klassen sollten wie folgt aussehen:

class User { 

     static hasOne = [employee: Employee] 

     static constraints = { 
       employee(nullable: true) 
     } 
} 

class Employee { 
    User supervisor // represents a supervisor 
    static belongsTo = [user: User] 

    static constraints = { 
     supervisor(nullable:true) 
    } 
} 

Es könnte schön sein, zu wissen, wie Sie Ihre DB-Struktur ist. Auf diese Weise werden alle Fremdschlüssel in der Angestelltentabelle gespeichert. Aber natürlich könnten Sie von beiden Entitäten navigieren. Wenn Sie eine andere Struktur haben, können Sie Ihre aktuelle Datenbank mit diesem Modell abbilden. Siehe this

employee.user 
user.employee 
+0

Vielen Dank für Ihre Antwort! Ich habe Ihren Code in Grails 3.2.0 versucht, aber es führt immer noch dazu, dass der Spalte supervisor_id der Tabelle employee ein NOT NULL hinzugefügt wird, trotz der Bedingung nullable: true. Wie bei dem Objekt "mappedBy on" ist dies ein Link von älterem Code, bei dem die Eins-zu-Eins-Zuordnung optional war und die Eigentümerseite umgekehrt war (der Fremdschlüssel war jedoch immer auf der Benutzerseite). – Rado

+0

Die wichtige Sache, die zu beachten ist, ist, dass Grails selbst die Nullable-Einschränkung (sogar mit meinem ursprünglichen "schlechten" Code) berücksichtigt. Wenn Sie also gegen ein vorhandenes oder manuell erstelltes Datenbankschema laufen, funktioniert es wie erwartet. Aber es ist das hbm2ddl-Schema, das falsch generiert wird, wenn auf diese Spalten NOT NULL angewendet wird, und dies bricht unsere Integrationstests, die mit einer In-Memory-H2-Datenbank ausgeführt werden. – Rado

+0

Gern geschehen. Ich werde versuchen, es in ein paar Stunden zu reproduzieren und werde Sie wissen lassen. – quindimildev