views:

261

answers:

2

OK here is stripped down version of what I have in my app

Artist domain:

class Artist {

    String name
    Date lastMined
    def artistService

    static transients = ['artistService']
    static hasMany = [events: Event]

    static constraints = {
        name(unique: true)
        lastMined(nullable: true)
    }

    def mine() {
        artistService.mine(this)
    }
}

Event domain:

class Event {

    String name
    String details
    String country
    String town
    String place
    String url
    String date

    static belongsTo = [Artist]
    static hasMany = [artists: Artist]

    static constraints = {
        name(unique: true)
        url(unique: true)
    }
}

ArtistService:

class ArtistService {

    def results = [
        [
            name:"name",
            details:"details",
            country:"country",
            town:"town",
            place:"place",
            url:"url",
            date:"date"
        ]
    ]

    def mine(Artist artist) {
        results << results[0] // now we have a duplicate
        results.each {
            def event = new Event(it)
            if (event.validate()) {
                if (artist.events.find{ it.name == event.name }) {
                    log.info "grrr! valid duplicate name: ${event.name}"
                }
                artist.addToEvents(event)
            }
        }

        artist.lastMined = new Date()
        if (artist.events) {
            artist.save(flush: true)
        }
    }
}

In theory event.validate() should return false and event will not be added to artist, but it doesn't.. which results in DB exception on artist.save()

Although I noticed that if duplicate event is persisted first everything works as intended. Is it bug or feature? :P

+1  A: 

Which version of Grails? I've just tested this code in the Grails 1.3.1 console:

new Book(title: "Misery", author: "Stephen King").save()
new Book(title: "The Shining", author: "Stephen King").save()
new Book(title: "Colossus", author: "Niall Ferguson").save(flush: true)

def b = new Book(title: "Colossus", author: "Stephen King")
assert !b.validate()
println b.errors

The assertion passed and the last line generated output like:

org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'Book' on field 'title': rejected value [Colossus]; codes [Book.title.unique.error.Book.title,...

Perhaps it was a bug that's now fixed?

Peter Ledbrook
+1  A: 

You should replace artist.addToEvents(event) by artist.addToEvents(event).save() and it will work. Till you didn't call save() method, the validation will not take into account the new created event

fabien7474
Checked it on a testing app - works like a charm, on my actual app - still throws duplicate entry exception. Only save(flush: true) eliminates the problem :|
rukoche