2009-12-24 9 views
7

Tôi đang viết một plugin grails và tôi cần phải móc vào phương thức save() miền để thực hiện một số logic sau khi lưu. Tôi cần phải làm điều này trên nhiều lớp miền. Tôi đang cố gắng tránh các sự kiện ngủ đông trong trường hợp người dùng plugin không sử dụng chế độ ngủ đông với GORM.Hooking vào đối tượng Grails Domain save()

Tôi đã thử nhiều thứ nhưng dưới đây là những gì tôi nghĩ nên có cơ hội tốt nhất khi làm việc. Trong mọi trường hợp grailsSavenull. Tôi có thể làm cái này như thế nào?

def doWithDynamicMethods = { ctx -> 
    application.domainClasses.each { dc -> 
     def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[]) 

     domainClass.metaClass.save = { Map params -> 
     grailsSave.invoke(delegate, [params] as Object[]) 
     println "Saved object, now do my thing" 
     //... 
     } 
    } 
} 

Tôi đã sau đây đặt trong * Lớp Plugin.groovy tôi:

def dependsOn = [domainClass: '1.1 > *', hibernate: '1.1 > *'] 
def loadAfter = ['hibernate'] 

Trả lời

6

Tôi không thể tham chiếu thành công đến phương thức save() trong khi khởi chạy plugin/ứng dụng; Tôi không biết tại sao. Thay vào đó, tôi quyết định tạo trình nghe cho các sự kiện ngủ đông sau khi chèn, cập nhật và xóa. Điều này post bởi Sean Hartsock liên quan đến việc kiểm tra Logging plugin là một mồi hoàn hảo để làm điều đó.

Dưới đây là các ý chính của Listener:

class MyListener implements PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener, Initializable { 

     public void onPostInsert(final PostInsertEvent event) { 
      // logic after insert 
      return 
     } 

     public void onPostUpdate(final PostUpdateEvent event) { 
      // logic after update 
      return 
     } 

     public void onPostDelete(final PostDeleteEvent event) { 
      // logic after delete 
      return 
     } 


     public void initialize(final Configuration config) { 
      return 
     } 
    } 

Sau đó, trong * GrailsPlugin.groovy:

def doWithApplicationContext = { applicationContext -> 

    // add the event listeners for reindexing on change 
    def listeners = applicationContext.sessionFactory.eventListeners 
    def listener = new MyListener() 

    ['postInsert', 'postUpdate', 'postDelete'].each({ 
     addEventTypeListener(listeners, listener, it) 
    }) 

} 


// copied from http://hartsock.blogspot.com/2008/04/inside-hibernate-events-and-audit.html 
private addEventTypeListener(listeners, listener, type) { 
    def typeProperty = "${type}EventListeners" 
    def typeListeners = listeners."${typeProperty}" 

    def expandedTypeListeners = new Object[typeListeners.length + 1] 
    System.arraycopy(typeListeners, 0, expandedTypeListeners, 0, typeListeners.length) 
    expandedTypeListeners[-1] = listener 

    listeners."${typeProperty}" = expandedTypeListeners 
} 

Khá đơn giản vào cuối ngày ...

+0

Shawn và kiểm tra Logging plugin đá của mình. –

+0

Cảm ơn bạn đã chia sẻ! Tôi đã lười biếng để tìm cái này của tôi. – Kimble

1

Này sẽ không tốt nhất được bổ sung vào lớp dịch vụ sở hữu các đơn vị của công việc? Đó là nơi mà thành ngữ Spring/Grails bình thường sẽ có logic như vậy. Bạn không cần phải sửa đổi lưu.

+0

Mặc dù tôi đang xây dựng tính năng cắm để người khác sử dụng. Logic của tôi có thể rất tốt trong một dịch vụ nhưng điểm mà nó cần phải thực hiện là tiết kiệm. Thanks – mbrevoort

+0

Ý tưởng ủy thác một lô logic liên quan trực tiếp đến miền đến tầng khác là một trong những phiền toái lớn nhất trong mùa xuân, và đó là lý do tại sao Java có danh tiếng về sự phức tạp hóa sự phức tạp. –

+0

Làm thế nào để một đối tượng miền riêng biệt biết khi nào nó là một phần của một đơn vị công việc lớn hơn và khi nào nó không? – duffymo

2

Có ba phiên bản khác nhau của lưu thêm vào metaclass,

save(Map) 
save(Boolean) 
save() 

Mà một trong những bạn đang gọi trong thử nghiệm của bạn? Bạn cần phải thêm mã cho mỗi mã.

Một điều để kiểm tra là liệu plugin của bạn đang chạy sau khi các plugin ngủ đông mà thêm ba phương pháp để các metaclass

cổ vũ

Lee

+0

Cảm ơn Lee, Tôi nghĩ rằng tôi đang gặp sự cố khi buộc plugin tải sau khi ngủ đông. Nếu tôi chạy trong doWithDynamicMethods, mọi nỗ lực gọi hàm pickMethod đều là null. Nếu tôi chạy trong bảng điều khiển grails họ không phải là null. Tôi có điều này trong plugin của tôi nhưng không có may mắn: def dependsOn = [domainClass: '1.1> *', hibernate: '1.1> *'] def loadAfter = ['hibernate'] – mbrevoort

+0

Tải trọng mmSau đây là thứ bạn muốn - nó có cần phải là tải tĩnhSau = ['hibernate'] – leebutts

+0

tĩnh không hoạt động hay không. Lạ lùng, tôi mới nhận thấy Robert Fischer đã cố gắng làm những việc tương tự với save() trong plugin GORM Labs của mình nhưng đã nhận xét đoạn mã trong các phiên bản trước và không tồn tại trong phiên bản gần đây nhất. Bất kỳ ý tưởng nào về cách tiếp cận khác nhau này? – mbrevoort

2

có một cái nhìn tại các plugin Falcone Util. Plugin này cho phép bạn nối vào các sự kiện Hibernate (xem tài liệu ở cuối trang). Tôi không biết nếu điều này là chính xác những gì bạn muốn, nhưng bạn có thể nhận được một số gợi ý.

Ps! Tôi không nghĩ rằng plugin này hoạt động với Grails 1.2.

+0

Cảm ơn bạn đời, plugin đó trông tuyệt vời. Sẽ tuyệt vời nếu loại khả năng sự kiện này có sẵn trong lõi. – mbrevoort

2

Đây là một vấn đề tối ưu hóa sớm: các phiên bản cũ của Groovy đã nghiêm túc trừng phạt MetaClass mangling, và vì vậy GORM không thêm tất cả ma thuật của nó cho đến khi nó phát hiện ra sự cần thiết.

Giải pháp dễ nhất là để plugin của bạn phụ thuộc vào GORM Labs (Tôi làm việc xung quanh nó ở đó). Các giải pháp thay thế là để kích hoạt methodMissing bằng tay (mà sẽ được nhân đôi công việc tôi đã làm). Xem tài liệu GORM Labs để biết chi tiết về cách tôi thực hiện điều đó.

1

Các phương pháp GORM bổ sung được khởi tạo lười biếng trong lần gọi đầu tiên tới bất kỳ phương thức nào trong số chúng. Để khởi tạo chúng trong doWithDynamicMethods chỉ cần gọi một trong những phương pháp tĩnh trên lớp miền của bạn (es):

def doWithDynamicMethods = { ctx -> 

    application.domainClasses.each { dc -> 

     // call any static method to initialize dynamic gorm methods 
     dc.clazz.count() 

     def grailsSave = dc.metaClass.pickMethod('save', [Map] as Class[]) 
     //... 
    } 
} 

phương pháp của bạn tiết kiệm() sẽ có sẵn ngay bây giờ. Vì điều này được gọi là lúc khởi động một số nên không phải là vấn đề lớn.