2012-10-15 12 views
17

Powiedzmy mam grails klasy domeny, która wygląda jakGrails hasOne vs zmiennej bezpośrednim członkiem

class Person { 
    Address address 
} 

mogę też zadeklarować ją jako

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

Drugi sposób ruszy klucz obcy do Tabela adresów, a nie tabela osób.

Jakie są praktyczne zalety (lub wady) robienia tego w jedną lub w drugą stronę? O ile mi wiadomo, obaj będą używać obcych kluczy, to tylko kwestia, gdzie mieszka zagraniczny klucz.

Odpowiedz

25

Jeśli klucz obcy istnieje w tabeli adresów, wówczas ten adres może mieć tylko jedna osoba. Jeśli klucz obcy znajduje się na stole osoby, wiele osób może mieć ten sam adres.

Nie chodzi o to, która droga jest lepsza/gorsza. Chodzi o to, jaki jest właściwy sposób modelowania danych.

+0

To ma sens, dzięki. Przepraszam za to trochę brzęczenia mózgu. Zaplątałem się w mechanizmy grails i nie cofnąłem się, by myśleć o tym z perspektywy bazy danych. –

21

Używam hasOne w Grails jako szczególnie mylące. Na przykład, pytanie dotyczy tego, co się dzieje, gdy związek Toone jest zadeklarowana następująco:

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

Jak stwierdzono powyżej, powoduje person_id klucz obcy do stawienia się w tabeli adres, co oznacza, że ​​każdy adres może wskazywać tylko na jedna osoba. To, co uważam za dziwne, to to, że chociaż kod jest zapisany jako "Osoba ma jeden adres", faktycznym rezultatem jest to, że "Adres ma jedną osobę".

W rzeczywistości, zdefiniowane wyłącznie jak wyżej, nie ma niczego (na poziomie bazy danych), które uniemożliwiłoby wykrycie więcej niż jednego rekordu Adresacji tej samej Osobie, co oznacza, że ​​osoba faktycznie nie musi mieć jednego adresu. .

Co ciekawe, można uzyskać taką samą reprezentację bazy jeśli stworzył klasę adresową tak:

class Address { 
    Person person 
} 

person_id klucz obcy będzie w tabeli adresów, tak jak w poprzednim przykładzie, ale oczywiście, nie można uzyskać od osoby do adresu w kodzie, nie definiując w jakikolwiek sposób tej relacji.

Interesujące jest również to, że jeśli modelowałeś wiele relacji od osoby do adresu w bazie danych, używałbyś tego samego układu tabeli. Wstawisz klucz podstawowy rodzica (id_osobisty) do tabeli podrzędnej. Z perspektywy bazy danych, użycie hasOne tworzy taką samą strukturę, jaką tworzy wiele relacji.

Oczywiście nie tworzymy tylko tabel bazy danych, tworzymy klasy domenowe Grails, które mają pewne zachowania związane z nimi, i pewne egzekwowanie semantyki relacji. W tym konkretnym przykładzie biznesowym prawdopodobnie nie chcesz udostępniać tego samego rekordu adresu wielu osobom, chcesz tylko przechowywać adres oddzielnie (może przygotować się na dzień, w którym dana osoba ma wiele adresów). pewnie bym głosował za takim podejściem:

class Person { 
    Address address 

    static constraints = { 
     address unique:true 
    } 
} 

address_id klucz obcy będzie w tabeli osoby, a UNIQUE wymusi że żadne dwie osoby są zapisy wskazujące na ten sam adres.

+2

Naprawdę interesujące, dzięki za przemyślenia! –

+0

Wygląda na to, że 'hasOne' ma wpływ na wydajność (przynajmniej w wersji 2.2.0, z którą utknąłem). Profilowałem i okazało się, że stowarzyszenie było leniwie załadowane, chociaż nie używałem go, co spowodowało wiele niepotrzebnych wycieczek do DB. Przełączenie go na zmienną członkowską najwyraźniej wyeliminowało to. –

7

Proponuję Po ...

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

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

osoba ma jeden adres i adres należący do jednej osoby.

W ten sposób, po usunięciu osoby, adres zostanie również usunięty, bez problemów.

Myślę, że jest to lepszy sposób na zrobienie tego.

+0

Chociaż domy nie są zazwyczaj usuwane po śmierci: D –

6

Osoba "hasOne" Adres i Adres "belongsTo" THE Osoba.

Posiadanie obcego klucza w tabeli "dziecko" ma więcej sensu, ponieważ w ten sposób dziecko mogłoby się zepsuć, jeśli brakuje rodzica. Osoba Osoba może istnieć bez adresu, ale "adres osoby" bez osoby nie ma sensu. Tak więc adres Adres powinien być słabszą stroną relacji.

Robiąc to w ten sposób w grailsach, oba byty będą miały odniesienie do siebie, aby nie było dziwnie. Również domyślne zachowanie kaskadowych będzie zapisywać i usuwać Adres kiedy zapisać Osoba ale jeśli chcesz usunąć AdresOsoba pozostaną zapisane.

Powiązane problemy