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()
精彩评论