如何全局设置所有Grails域类的cascade为false并支持单独保存配置
Got it, let's break down your two Grails cascade requirements with practical, actionable solutions:
1. Global Setting: Disable Cascade for All Domain Classes
Grails uses Hibernate under the hood, where cascade behavior is defined via string values (not booleans) — 'none' is equivalent to what you're calling "cascade=false". Here are two solid approaches to apply this globally:
Option 1: Create a Base Domain Class
Define an abstract base class with the global cascade setting, then have all your domain classes inherit from it. This keeps your code DRY and easy to maintain:
// grails-app/domain/com/yourpackage/BaseDomain.groovy abstract class BaseDomain { static mapping = { // Apply 'none' cascade to all associations across the domain class '*' cascade: 'none' } }
Then extend this base class in every domain:
class Book extends BaseDomain { String title Author author // ... other fields and mappings }
Option 2: Modify Domain Classes via Bootstrap
If you don't want to use a base class, you can iterate over all domain classes at app startup and update their cascade settings. Use the Bootstrap.groovy file:
// grails-app/init/BootStrap.groovy import grails.core.GrailsDomainClass class BootStrap { def grailsApplication def init = { servletContext -> grailsApplication.domainClasses.each { GrailsDomainClass domain -> // Set global cascade to 'none' for all associations domain.associations.each { assoc -> assoc.cascade = 'none' } // Alternatively, set it at the mapping level domain.mapping.cascade = 'none' } } }
2. Override Cascade for Specific Save Operations
Sometimes you need to bypass the global setting and enable/disable cascade for a one-off save. Here are two reliable methods:
Method 1: Temporarily Modify Domain Mapping
Adjust the cascade setting for the target association before saving, then revert it afterward to avoid affecting other operations:
// Example service or controller method def saveAuthorWithoutCascading(Author author) { // Store the original cascade value def originalCascade = Author.mapping.books.cascade try { // Disable cascade for the 'books' association Author.mapping.books.cascade = 'none' // Save the author without cascading to books author.save(flush: true, failOnError: true) } finally { // Revert to the original cascade setting Author.mapping.books.cascade = originalCascade } }
Method 2: Direct Hibernate Session Manipulation
For more control, you can interact directly with the Hibernate Session to adjust cascade behavior for the specific save:
import org.hibernate.SessionFactory import org.hibernate.engine.spi.CascadeStyle // Inject SessionFactory in your service/controller def sessionFactory def saveAuthorWithoutCascading(Author author) { def session = sessionFactory.currentSession def persister = session.getEntityPersister(Author.name, author) def collectionPersister = persister.getCollectionPersister('books') // Store original cascade style def originalStyle = collectionPersister.cascadeStyle try { // Set cascade to none for this operation collectionPersister.cascadeStyle = CascadeStyle.NONE author.save(flush: true, failOnError: true) } finally { // Restore original cascade style collectionPersister.cascadeStyle = originalStyle } }
Bonus: Quick Workaround for Simple Cases
If your association isn't mandatory, you can temporarily clear the association before saving, then restore it:
def saveAuthorWithoutCascading(Author author) { def tempBooks = author.books author.books = [] // Or null, depending on your mapping try { author.save(flush: true, failOnError: true) } finally { author.books = tempBooks } }
Just note this won't work if the association is marked as nullable: false.
内容的提问来源于stack exchange,提问作者Kapil Arora

