2012-10-15 10 views
17

Lassen Sie sich sagen, ich habe eine Domain-Klasse Grails, die wiegrails hasOne vs direkter Membervariable

class Person { 
    Address address 
} 

sieht ich es auch als

class Person { 
    static hasOne = [address:Address] 
} 

Der zweite Weg erklären könnte den Fremdschlüssel für die bewegen würde Adressentabelle statt der Personentabelle.

Was sind die praktischen Vorteile (oder Nachteile), dies in einer Weise gegen die andere zu tun? Soweit ich weiß, werden sie beide Fremdschlüssel verwenden, es kommt nur darauf an, wo der Fremdschlüssel lebt.

Antwort

25

Wenn der Fremdschlüssel in der Adresstabelle vorhanden ist, kann diese Adresse nur eine Person enthalten. Wenn sich der Fremdschlüssel in der Personentabelle befindet, können mehrere Personen die gleiche Adresse haben.

Es geht nicht darum, was besser/schlechter ist. Es geht darum, wie Sie Ihre Daten richtig modellieren.

+0

Das macht Sinn, danke. Tut mir leid, ein bisschen von einem Gehirn furze von mir hier. Ich wurde in die Grals-Mechanismen eingewickelt und trat nicht zurück, um aus einer Datenbankperspektive darüber nachzudenken. –

21

Ich finde die Verwendung von hasOne in Grails als besonders verwirrend. Zum Beispiel fragt diese Frage, was passiert, wenn eine TOONE Beziehung wie folgt erklärt:

class Person { 
    static hasOne = [address: Address] 
} 

Wie oben erwähnt, dies die person_id Fremdschlüssel verursacht in der Adresstabelle angezeigt werden, was bedeutet, dass jede Adresse nur Punkt eine Person. Was ich seltsam finde, ist, dass obwohl der Code als "eine Person hat eine Adresse" geschrieben wurde, das tatsächliche Ergebnis ist, dass "eine Adresse eine Person hat".

Und in der Tat, nur wie oben definiert, gibt es nichts (auf der Datenbank-Ebene) verhindert mehr als ein Address-Datensatz auf die gleiche Person zeigen, was bedeutet, dass eine Person nicht wirklich eine Adresse haben muss .

Interessanterweise würden Sie die gleiche Datenbank Darstellung erhalten, wenn Sie die Adresse Klasse wie folgt erstellt:

class Address { 
    Person person 
} 

Die person_id Fremdschlüssel in der Adresstabelle sein werden, so wie wie im vorherigen Beispiel, aber Natürlich können Sie nicht von der Person zur Adresse im Code gelangen, ohne diese Beziehung ebenfalls zu definieren.

Interessant ist auch, dass wenn Sie eine ToMany-Beziehung von Person zu Adresse in der Datenbank modellieren, Sie das gleiche Tabellenlayout verwenden würden. Sie würden den Primärschlüssel der Eltern (person_id) in die untergeordnete Tabelle einfügen. Aus einer Datenbankperspektive erzeugt die Verwendung von hasOne die gleiche Struktur, die eine toMany-Beziehung erzeugen würde.

Natürlich erstellen wir nicht nur Datenbanktabellen, sondern erstellen auch Grails-Domänenklassen, denen ein gewisses Verhalten zugeordnet ist, sowie eine Erzwingung der Beziehungssemantik. In diesem speziellen Geschäftsbeispiel möchten Sie wahrscheinlich nicht den gleichen Address-Datensatz für mehrere Personen freigeben, sondern Sie möchten die Adresse nur separat speichern (möglicherweise für den Tag, an dem eine Person mehrere Adressen hat). Ich würde wahrscheinlich für diesen Ansatz stimmen:

class Person { 
    Address address 

    static constraints = { 
     address unique:true 
    } 
} 

Die address_id Fremdschlüssel in der Tabelle Person sein werden, und die eindeutige Einschränkung erzwingt, dass keine zwei Personendatensätze an derselben Adresse zeigen.

+2

Wirklich interessant, danke für die Gedanken! –

+0

Und 'hasOne' scheint Performanceimplikationen zu haben (zumindest in 2.2.0, mit denen ich festhalte). Ich habe Profilerstellungen gemacht und festgestellt, dass der Verein faul geladen wurde, obwohl ich ihn nicht benutzte, was zu vielen unnötigen Fahrten in die DB führte. Wenn Sie es auf eine Elementvariable umstellen, scheint das beseitigt zu sein. –

7

schlage ich die folgende ...

class Person { 
    ... 
    static hasOne = [address: Address] 
} 

class Address { 
    ... 
    static belongsTo = [person: Person] 
} 

Eine Person, eine Adresse hat und die Adresse gehört zu einer Person.

Auf diese Weise, wenn Sie eine Person löschen, wird die Adresse auch gelöscht, ohne Probleme.

Ich denke, das ist der bessere Weg, dies zu tun.

+0

Obwohl Häuser normalerweise nicht gelöscht werden, wenn Sie sterben: D –

6

Die Person "hasOne" Adresse und die Adresse "belongsTo" die Person.

Das Vorhandensein des Fremdschlüssels in der "Kind" -Tabelle macht mehr Sinn, weil auf diese Weise das Kind brechen würde, wenn das Elternteil fehlt. Eine Person kann ohne ihre Adresse existieren, aber eine "Personenadresse" ohne eine Person ergibt keinen Sinn. So sollte die Adresse die schwächere Seite der Beziehung sein.

Auf diese Weise in Grals haben beide Entitäten den Bezug zueinander, so dass es sich nicht komisch anfühlt. Auch wird die Standard-Kaskadierung Verhalten speichern und löschen Sie die Adresse, wenn Sie die Person sparen, aber wenn Sie die Adresse die Person bleiben löschen möchten gespeichert.