سؤال

I am trying to clear out a collection and update it at the same time. It has children and finding the current items in the collection and deleting them asynchronously would save me a lot of time.

Step 1. Find all the items in the collection. Step 2. Once I know what the items are, fork a process to delete them.

def memberRedbackCriteria = MemberRedback.createCriteria()
    // #1 Find all the items in the collection.
    def oldList = memberRedbackCriteria.list { fetchMode("memberCategories", FetchMode.EAGER) }
    // #2 Delete them.
    Promise deleteOld = task {
        oldList.each { MemberRedback rbMember ->
              rbMember.memberCategories.clear()
              rbMember.delete()
         }
 }

The error message is: Illegal attempt to associate a collection with two open sessions

I am guessing that because I find the items, then fork, this creates a new session so that the collection is built before forking and a new session is used to delete the items.

I need to collect the items in the current thread, otherwise I am not sure what the state would be.

هل كانت مفيدة؟

المحلول 2

Found a solution. Put the ids into a list and collect them as part of the async closure.

Note also that you cannot reuse the criteria as per http://jira.grails.org/browse/GRAILS-1967

// #1 find the ids
def redbackIds = MemberRedback.executeQuery(
                'select mr.id from MemberRedback mr',[])

// #2 Delete them.
Promise deleteOld = task {
       redbackIds.each { Long rbId ->
            def memberRedbackCriteria = MemberRedback.createCriteria()
            MemberRedback memberRedback = memberRedbackCriteria.get {
                idEq(rbId)
                fetchMode("memberCategories", FetchMode.EAGER) }
            memberRedback.memberCategories.clear()
            memberRedback.delete()
       }
 }
 deleteOld.onError { Throwable err ->
      println "deleteAllRedbackMembers An error occured ${err.message}"
 }

نصائح أخرى

Note that using one async task for all the deletions is effectively running all the delete operations in series in a single thread. Assuming your database can handle multiple connections and concurrent modification of a table, you could parallelize the deletions by using a PromiseList, as in the following (note untested code follows).

def deletePromises = new PromiseList()
redbackIds.each { Long rbId ->
    deletePromises << MemberRedback.async.task {
        withTransaction {
            def memberRedbackCriteria = createCriteria()
            MemberRedback memberRedback = memberRedbackCriteria.get {
                idEq(rbId)
                fetchMode("memberCategories", FetchMode.EAGER) }
            memberRedback.memberCategories.clear()
            memberRedback.delete()
        }
    }
}
deletePromises.onComplete { List results ->
    // do something with the results, if you want
}
deletePromises.onError { Throwable err ->
    // do something with the error
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top