2012-10-15 30 views
17

Hãy nói rằng tôi có một lớp miền grails trông giống nhưgrails hasOne vs biến thành viên trực tiếp

class Person { 
    Address address 
} 

tôi cũng có thể khai báo nó như

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

Cách thứ hai sẽ di chuyển phím nước ngoài cho Bảng địa chỉ thay vì bảng người.

Lợi ích thực tế (hoặc bất lợi) của việc này theo cách này so với cách khác là gì? Theo như tôi hiểu, cả hai đều sẽ sử dụng các khóa ngoại, đó chỉ là vấn đề của khóa ngoại quốc.

Trả lời

25

Nếu khóa ngoại tồn tại trên bảng địa chỉ, thì địa chỉ đó chỉ có thể có một người. Nếu khóa ngoài nằm trên bảng người, nhiều người có thể có cùng địa chỉ.

Đó không phải là cách tốt hơn/tệ hơn. Đó là cách chính xác để mô hình hóa dữ liệu của bạn.

+0

Điều đó có ý nghĩa, cảm ơn. Xin lỗi một chút của một fart não từ tôi ở đây. Tôi đã bị cuốn vào cơ chế grails và không lùi bước suy nghĩ về nó từ góc độ cơ sở dữ liệu. –

21

Tôi thấy việc sử dụng hasOne trong Grails đặc biệt khó hiểu. Ví dụ, câu hỏi này hỏi những gì sẽ xảy ra khi một mối quan hệ Toone được khai báo như sau:

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

Như đã trình bày ở trên, điều này gây ra chìa khóa nước ngoài person_id xuất hiện trong bảng địa chỉ, có nghĩa là mỗi Địa chỉ chỉ có thể điểm mà tại một người. Những gì tôi thấy kỳ lạ, sau đó, là mặc dù mã được viết là "một người có một địa chỉ", kết quả thực tế là "một địa chỉ có một người". Trên thực tế, chỉ được định nghĩa ở trên, không có gì (ở cấp cơ sở dữ liệu) ngăn nhiều hơn một bản ghi Địa chỉ trỏ đến cùng một Người, có nghĩa là một Người không thực sự phải có một Địa chỉ sau tất cả .

Điều thú vị là bạn sẽ có được đại diện cơ sở dữ liệu tương tự nếu bạn tạo lớp Địa chỉ như thế này:

class Address { 
    Person person 
} 

Chìa khóa ngoại person_id sẽ nằm trong bảng địa chỉ, giống như như trong ví dụ trước, nhưng rõ ràng, bạn không thể nhận được từ Người đến Địa chỉ trong mã mà không xác định mối quan hệ đó theo một cách nào đó.

Cũng thú vị là, nếu bạn đã mô hình hoá mối quan hệ toMany từ Người sang Địa chỉ trong cơ sở dữ liệu, bạn sẽ sử dụng cùng một bố cục bảng. Bạn sẽ đặt khóa chính của cha mẹ (person_id) vào bảng con. Từ phối cảnh cơ sở dữ liệu, sử dụng hasOne sẽ tạo cấu trúc tương tự mà mối quan hệ toMany sẽ tạo ra. Tất nhiên, chúng tôi không chỉ tạo ra các bảng cơ sở dữ liệu, chúng tôi đang tạo ra các lớp miền Grails có một số hành vi liên kết với chúng, và một số thực thi ngữ nghĩa mối quan hệ. Trong ví dụ kinh doanh cụ thể này, có thể bạn không muốn chia sẻ cùng một bản ghi Địa chỉ với nhiều Người, bạn chỉ muốn lưu trữ Địa chỉ riêng biệt (có thể chuẩn bị cho ngày khi một Người có nhiều Địa chỉ). Tôi có lẽ muốn bỏ phiếu cho phương pháp này:

class Person { 
    Address address 

    static constraints = { 
     address unique:true 
    } 
} 

Chìa khóa ngoại address_id sẽ nằm trong bảng Person, và hạn chế duy nhất sẽ thi hành mà không có hai hồ sơ Người đang trỏ tại cùng một địa chỉ.

+2

Thực sự thú vị, cảm ơn những suy nghĩ! –

+0

Và 'hasOne' dường như có ý nghĩa về hiệu suất (ít nhất là trong 2.2.0, mà tôi bị mắc kẹt). Tôi đã được profiling và thấy rằng các hiệp hội đã được lazily tải, _ mặc dù tôi đã không sử dụng it_, dẫn đến rất nhiều chuyến đi không cần thiết cho DB. Chuyển nó sang một biến thành viên dường như đã loại bỏ điều đó. –

7

Tôi đề nghị sau đây ...

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

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

Một người có một địa chỉ, địa chỉ thuộc về một người.

Bằng cách này, khi bạn xóa một người, địa chỉ cũng sẽ bị xóa mà không gặp sự cố.

Tôi nghĩ đây là cách tốt hơn để thực hiện việc này.

+0

Mặc dù ngôi nhà thường không bị xóa khi bạn chết: D –

6

Các Person "hasOne" Địa chỉĐịa chỉ "belongsTo" các Person.

Có khóa ngoại trên bảng "con" có ý nghĩa hơn vì cách này con sẽ bị hỏng nếu cha mẹ bị thiếu. A Người có thể tồn tại mà không có địa chỉ của nó nhưng "địa chỉ của một người" mà không có người không có ý nghĩa. Vì vậy, Địa chỉ phải là mặt yếu của mối quan hệ.

Làm theo cách này trong grails cả hai thực thể sẽ có tham chiếu với nhau để nó sẽ không cảm thấy lạ. Ngoài ra, hành vi xếp tầng mặc định sẽ lưu và xóa Địa chỉ khi bạn lưu Người nhưng nếu bạn muốn xóa Địa chỉNgười sẽ vẫn được lưu.

Các vấn đề liên quan