2010-06-29 23 views
5

Trong grails, tôi có thể thực hiện một N: 1 mối quan hệ như thế này:Khi nào có nên sử dụng cho các mối quan hệ N: 1 trong các lớp miền grails?

class Parent { hasMany = [children:Child] } 
class Child { belongsTo = [parent:Parent] } 

Bây giờ (nếu addTo và removeFrom luôn là sử dụng đúng cách) tôi có thể nhận trẻ em của cha mẹ qua parent.children.

Nhưng tôi cũng có thể làm điều đó mà không hasMany:

class Parent { } 
class Child { belongsTo = [parent:Parent] } 

Sau đó, tôi phải sử dụng Child.findAllByParent (mẹ) để có được tất cả trẻ em.

Câu hỏi của tôi: Có bất kỳ lý do quan trọng nào tại sao tôi nên sử dụng hasMany nếu có thể truy vấn con của cha mẹ theo cách thứ hai không?

Tôi đoán rằng đôi khi nó dễ dàng hơn (và có lẽ nhanh hơn nếu háo hức tìm nạp cùng với phụ huynh?) Để chỉ tham khảo parent.children, nhưng mặt khác Danh sách này có thể trở nên khá dài khi có nhiều trẻ em. Và những gì tôi không thích về hasMany hoặc là bạn luôn luôn phải chăm sóc về addTo hoặc removeFrom hoặc để xóa phiên sau khi thêm một đứa trẻ mới với một phụ huynh để grails hiện điều này tự động ...

Is câu trả lời rằng bạn chỉ nên sử dụng hasMany nếu có rất ít trẻ em và không sử dụng nó nếu có nhiều (vì lý do hiệu suất), hoặc là có nhiều hơn đằng sau nó?

Trả lời

8

Sử dụng hasMany so với dependsTo có liên quan nhiều hơn đến hành vi xếp tầng mà bạn muốn chỉ định khi cập nhật/xóa xảy ra. Trong ví dụ thứ hai của bạn, tầng được đặt thành TẤT CẢ ở bên con và KHÔNG ở bên mẹ. Nếu bạn xóa một đứa trẻ, không có gì sẽ xảy ra trên phụ huynh. Nếu bạn xóa phụ huynh, tất cả trẻ em sẽ tự động bị xóa.

Trong ví dụ đầu tiên, tầng được đặt thành TẤT CẢ ở bên mẹ và SAVE-UPDATE ở phía bên con. Vì vậy, bây giờ bạn có thể làm điều gì đó như:

parent.addToChildren(child1) 
parent.addToChildren(child2) 
parent.addToChildren(child3) 
parent.save(flush:true) 

Và khi bạn lưu cha mẹ, tất cả các trẻ em sẽ được cập nhật.

Chạm vào một cái gì đó bạn không hỏi, bạn cũng có thể có lẽ có cái gì đó như:

class Parent { hasMany = [children:Child] } 
class Child { Parent parent } 

Nếu bạn xác định các mối quan hệ từ trẻ em đến phụ huynh trong cách này, bạn sẽ cần phải tự quản lý các đối tượng trẻ em tham chiếu đến cha mẹ khi bạn xóa cha mẹ *. (* Này sửa chữa một tuyên bố trước đó được chứng minh là không chính xác)

Vì vậy, hasMany/belongsTo có hai cân nhắc chính:

  1. Những loại chiến lược tầng nào bạn muốn thực thi trên cập nhật/xóa
  2. Bạn có nhiều khả năng truy cập dữ liệu như thế nào, nếu bạn mong muốn truy xuất một tập hợp con cho cha mẹ, có phương thức parent.getChildren() khá thuận tiện.

UPDATE:

Tôi cũng muốn làm rõ, GORM sẽ không háo hức nạp khi bạn sử dụng hasMany; theo mặc định, GORM sử dụng chiến lược tìm nạp lười để nó không nhận được trẻ em cho đến khi cố gắng truy cập vào cấp độ gốc.trẻ em

Nếu bạn muốn một hiệp hội để được háo hức lấy theo mặc định, bạn có thể chỉ định việc lập bản đồ thích hợp:

class Parent { 
    hasMany = [children:Child] 
    static mapping = { 
    children lazy:false 
    } 
} 

Cuối cùng, bạn nói rằng bạn không thích mà bạn phải lo lắng về các addTo/removeTừ phía hasMany. Bạn không cần phải làm điều này nếu bạn tiết kiệm với tuôn ra: đúng sự thật.

def parent = Parent.get(id) 
def child = new Child(name:'child1', parent:parent) 
if(child.save(flush:true)) { 
    // both sides of the relationship should be good now 
} 

EDIT: trật tự đảo ngược của giá trị mặc định cascade con/phụ huynh và quan niệm sai lầm về cách khắc phục GORM xử lý các mối quan hệ mà không belongsTo

+0

Cảm ơn bạn, vì vậy, đó là tất cả về hành vi xếp tầng. Bạn có nói rằng hiệu suất không phải là một vấn đề khi danh sách quản lý cho trẻ em trở nên rất lớn? Về cập nhật của bạn, tiếc là tiết kiệm với tuôn ra: đúng là không đủ cho tự động addTo/removeFrom. Như tôi đã học trong vấn đề grails được gửi của tôi https://cvs.codehaus.org/browse/GRAILS-6356, bạn cần xóa phiên với sessionFactory.currentSession.clear() nếu bạn muốn đạt được điều này WITHIN một kiểm tra hoặc một bộ điều khiển . Trong quá trình sản xuất giàn giáo, nó hoạt động vì phiên được xóa sau hành động lưu/cập nhật của Trẻ. –

+0

Chỉ cần thử nghiệm nó và có vẻ như việc xóa tầng là ngược lại với những gì bạn nói lúc đầu: Trong ví dụ ĐẦU TIÊN của tôi (với hasMany), khi xóa một phụ huynh, tất cả trẻ em cũng bị xóa. Trong ví dụ SECOND (không có hasMany), trẻ em phải được xóa thủ công trước khi xóa một phụ huynh. –

+0

Trên thực tế thử nghiệm của tôi cũng tiết lộ rằng trong ví dụ của bạn với hasMany và không có thuộc tính, việc xóa của cha mẹ KHÔNG gây ra cho trẻ em có một phụ huynh rỗng nhưng ném một DataIntegrityViolationException ... Tôi phải đặt cha mẹ của trẻ em để null trước khi xóa . –

0

Great câu hỏi và câu trả lời chấp nhận hiện nay là tốt cố định. Có một sự cân nhắc về hiệu suất quan trọng khác, đó là những gì sẽ xảy ra khi bạn thêm và lưu một đứa trẻ mới. Trong ví dụ đầu tiên của bạn, Grails theo mặc định phải tải toàn bộ danh sách các trẻ em từ cơ sở dữ liệu trước khi chèn mới vào Set, để đảm bảo tính duy nhất. Trong trường hợp thứ hai, nó không, dẫn đến hiệu suất tốt hơn nhiều. Bạn có thể giải quyết hành vi này trong ví dụ đầu tiên của mình bằng cách xác định trẻ em là 'Bộ sưu tập' theo http://grails.org/doc/latest/guide/single.html#sets,ListsAndMaps

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