简体   繁体   中英

Grails save(flush:true) not immediately persisting to database

I am using following code -

Topic topic = new Topic()
topic.name = "y u no save"
topic.save(flush:true, failOnError:true)

def promiseList = new PromiseList()
subtopicNames.each { sName ->
  promiseList << Topic.async.task {
       Subtopic subtopic = new Subtopic()
       subtopic.name = sName
       /* ... long running tasks like web service call ... */
       log.info("Topic Id : $topic.id")
       subtopic.topic = topic
       subtopic.save(flush: true, failOnError: true)
  }
}

def subtopics = promiseList.get()

I get this error-

Detail: Key (topic_id)=(517333) is not present in table "topic".; nested exception is org.postgresql.util.PSQLException: ERROR: insert or update on table "subtopic" violates foreign key constraint "fkfd7d3e7098cf2d58"
  Detail: Key (topic_id)=(517333) is not present in table "topic".

When I check database for topic with id 517333, it actually doesn't exist, while the log in aync.task block prints 'Topic Id : 517333'. What is going on here, how to force the topic save when required.

Topic - 

class Topic {
  String name
  static hasMany = [subtopics: Subtopic]
}

Subtopic - 

class Subtopic {
  String name
  static belongsTo = [topic: Topic]
}

The way to add domain instances into a collection that uses a hasMany relationship is to add the child domain to the parent class' collection. Try this :

def promiseList = new PromiseList()
def topic = new Topic(name: 'main topic')
topic.save(failOnError: true, flush: true)
def subtopics = ['subtopic 1', 'subtopic 2']

subtopics.each { topicName ->
    promiseList << Topic.async.task {
        Subtopic subtopic = new Subtopic(name: topicName)
        // adding to the topic will cascade saves of the subtopics by default.
        topic.addToSubtopics(subtopic)
        /* ... long running tasks like web service call ... */
        return subtopic
    }
}

// wait for tasks to complete
def subtopicList = promiseList.get()

// Saving the topic will cascade saves of the child subtopics
topic.save(failOnError: true, flush:true)

If you want to still do it your way, you may disable the constraint on subtopic's topic property to allow for null :

class Subtopic {
    //...
    static constraints = {
        topic nullable: true
    }
}

Then you can do :

Subtopic subtopic = new Subtopic(name : topicName)
subtopic.save(flush:true)

And, after the promises are synchronized :

def subtopicList = promiseList.get()
subtopicList.each {
    topic.addToSubtopics(it)
}
topic.save(failOnError: true, flush:true)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM