开发者

Problems with deleting objects in Grails - slow, and still not really deleted

This is probably a rookie mistake, so forgive me in advance. I have searched high and low for a solution, but without result - so I thourght I'd add my first post here :-)

I have two domain classes, one called Domain and one called Page. As below code shows, the Domain has many Page(s).

class Domain {
          ...
    static hasMany = [  pages : Page, ... ]
    static mapping = {
        pages lazy:true
    }
}

class Page {
    String identifier
    ...
    static belongsTo = [ domain : Domain ]
    static hasMany = [ ... ]
    static constraints = {
        identifier(blank:false, unique:'domain')
    }
    static mapping = {
        ...
        domain lazy:true
    }
}

My application has a long algorithm that amongst other things creates Pages on a Domain. If you run the algorithm with the same arguments as a previous run, it will start by deleting all pages created by the previous run before running the algorithm again.

I have two problems:

Problem #1 When I delete a specific Page from a Domain using:

def domain = page.domain
domain.removeFromPages(page);
page.delete()
domain.save(flush:true)

This causes Hibernate to fetch and load all pages of the domain, which ultimately fires several thousands queries (the domain has MANY pages). How am I improving perfomance on this? - Executing sql directly to de开发者_如何转开发lete the page make the database and hibernate get out of sync.

Problem #2 When I later create the page again:

def page = new Page(identifier:'...').save(failOnError:true)

I get the:

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session

Any help is welcome - I am losing my mind here :-/


I would suggest to think about a small redesign of your classes. First, remove the pages-collection from "Domain"

Class Domain {
  // no pages here
}

And then put a simple reference to "Domain" in "Page"

Class Page {    
    String identifier
    Domain domain
    ...
}

This makes the handling of your pages much easier. I don't know if this is really an option for you because you have to make changes to your existing code, but it can save you a lot of trouble with your large collections. There is also a presentation by Burt Beckwith about this.


For a batch delete, see this post by the IntelliGrape

I had to fetch and store holidays stored in a remote system, and on each fetch delete the ones I had stored locally and this came up like this:

Holiday.list()*.delete(flush:true)

The * is where all the magic happen. Note that you can restrict the number of items to delete with the list() method.

On a batch, note that you can also use the following to perform a batch.

def session = sessionFactory.openSession()
def tx = session.beginTransaction()

... 
for(holiday in holidays) {
        def h = new Holiday(..)
        session.save(h) 
}
sessionFactory.currentSession.flush()
tx.commit()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜