Search code examples
grailsgroovygrails-orm

Grails issue listing duplicate last names in associated list


I have a scaffolded Grails application with two domains, Person and Course. Person belongs to Course, and Course hasMany Persons. I have modified show.gsp for Course to list all of the Persons associated with the selected Course.

The problem that I'm running into is that the list which displays all Persons in a given Course does not show Persons with duplicate last names in the database. For example, if I have 4 persons: "John Doe", "Jane Doe", "Joe Doe", "Edward Smith", then the list will only show:

  • Jane Doe
  • Edward Smith

All of the 4 persons are present in the database, however. In addition, /person/list will show all of the names. So the problem is only with the list of persons associated with a Course. Please see the relevant code below. Any thoughts?

Person Domain:

class Person implements Comparable {

    static mapping = { sort lastName: "asc" }

    // Needed to sort association in Course domain (due to Grails bug)
    int compareTo(obj) {
        lastName.compareToIgnoreCase( obj.lastName );
    }

    String firstName
    String lastName
    String email

    Course course

    static belongsTo = [ course:Course ]

    static constraints = {
        firstName size: 1..50, blank: false
        lastName size: 1..50, blank: false
        email email: true
        course()
        firstName(unique: ['lastName', 'email'])
    }

    String toString() {
        return this.lastName + ", " + this.firstName;
    }
}

Course Domain:

class Course {

    int maxAttendance
    SortedSet persons

    static hasMany = [ persons:Person ]

    static mapping = {
        persons cascade:"all-delete-orphan"
    }

    def getExpandablePersonList() {
        return LazyList.decorate(persons,FactoryUtils.instantiateFactory(Person.class))
    }

    static constraints = {
        maxAttendance size: 1..3, blank: false
    }
}

Modified show.gsp for Course:

<g:if test="${courseInstance?.persons}">
                <br />
                <table>
                    <thead>
                        <tr>
                            <th>#</th>
                            <g:sortableColumn property="person"
                                title="${message(code: 'person.lastName.label', default: 'Person')}" />

                        </tr>
                    </thead>
                    <tbody>
                        <g:set var="counter" value="${1}" />
                        <g:each in="${courseInstance.persons}" status="i" var="p">
                            <tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
                                <td>
                                    ${counter}
                                </td>
                                <td class="property-value" aria-labelledby="persons-label"><g:link
                                        controller="person" action="show" id="${p.id}">
                                        ${p?.encodeAsHTML()}</td>

                            </tr>
                            <g:set var="counter" value="${counter + 1}" />
                        </g:each>
                    </tbody>
                </table>
            </g:if>

Solution

  • You've used a SortedSet for the association, and Person's compareTo considers two people with the same last name to be identical, thus the second and subsequent ones with the same last name won't be added to the set in the first place.