2012-03-26 4 views
2

Ich habe eine einfache bidirektionale Eins-zu-viele-Zuordnung, wie folgt, mit einer standardmäßigen Sortierreihenfolge auf der besitzenden Seite. Die Sortierreihenfolge scheint jedoch nicht angewendet zu werden. Ich benutze Grails v2.0.1 (Ich habe dieses Beispiel jetzt mit v1.3.7 repliziert).Grails: Sortierreihenfolge auf Eins-zu-Viele-Beziehung funktioniert nicht

package playground 

class User { 

    String name 

    static hasMany = [ posts : Post ] 

    static mapping = { 
     posts sort:'position' 
    } 
} 

und

package playground 

class Post { 

    int position = 1 
    String message 

    static belongsTo = [ user : User ] 
} 

hierfür ist die Integration Testcode ich es ausüben bin mit ...

def User user = new User(name:'bob') 
    user.addToPosts(new Post(position:2, message:'two')) 
    user.addToPosts(new Post(position:3, message:'three')) 
    user.addToPosts(new Post(position:1, message:'one')) 

    assertTrue user.validate() 
    assertFalse user.hasErrors() 
    assertNotNull user.save() 

    for (post in user.posts) { 
     log.debug "Post message> ${post.message}" 
    } 

Bitte nehmen Sie mich aus meinem Elend, dann ist es vermutlich offensichtlich etwas aber ich kann es nicht sehen! Vielen Dank.

+0

Es ist möglich, dass die Art nur dann angewandt wird, wenn es aus der Datenbank gezogen wird. Vielleicht versuchen Sie user.refresh() vor Ihrer for-Schleife, um zu sehen, ob das wahr ist? Es ist keine Lösung, aber es könnte die unterschiedliche Reihenfolge erklären. – Igor

+0

Das oder einen neuen Verweis auf es mit einem User.findByName ('bob'), um eine Hin-und Rückfahrt zu erzwingen, sollte wahrscheinlich nicht müssen, aber könnte hinzufügen, ein Flush: True zum Speichern sowie –

+1

Interessant. Flush: True hat nicht funktioniert, aber Benutzer.refresh() hat es getan. Das Seltsame ist, dass, wenn Sie den Benutzer wieder aus der Datenbank herausrufen (def User foundUser = User.get (user.id);)) dann iterieren Sie über die Posts, die es immer noch nicht in sortierter Reihenfolge macht - möglicherweise weil es erhalten wurde aus dem Cache (obwohl das Hinzufügen von flush: true auch dort nicht funktioniert). Dies ist nicht die erste Kuriosität, die ich bei Integrationstests gesehen habe ... beunruhigend. – ndtreviv

Antwort

0

Wenn Sie eine Liste anstelle eines Sets verwenden (Standard), wird das Framework die Bestellung für Sie übernehmen.

List posts = new ArrayList() 
static hasMany = [ posts : Post ] 
+1

Oder vielleicht ein SortedSet, um nützliche Set-Verhalten beizubehalten ... – ndtreviv

+0

@ j4y - mit einer Liste wird die Reihenfolge beibehalten. Was ich jedoch suche, ist die Möglichkeit, eine Sortierreihenfolge für ein Feld im Domänenobjekt ala [grails docs] zu deklarieren (http://grails.org/doc/2.0/guide/GORM.html#defaultSortOrder)) – owenrh

1

stellte sich heraus, das ein bisschen seltsam kanten Fall Verhalten ist, das ist wirklich ein Ergebnis der Art und Weise der Test geschrieben wird. Grundsätzlich passiert alles im Rahmen einer einzelnen Hibernate-Sitzung/txn (siehe oben). Daher holt der Test das gerade erstellte Objektdiagramm zurück (mit dem Satz außerhalb der Reihenfolge), anstatt Daten aus der Datenbank abzurufen.

Wenn Sie eine separate Transaktion erzwingen, erhalten Sie das von Ihnen gewünschte Verhalten, und die 'Bestellung von' funktioniert wie erwartet. Z.B.

User.withNewSession{ session -> 
    def User foundUser = User.get(user.id); 

    for (post in foundUser.posts) { 
     println "Post message> ${post.message}" 
    } 
} 

Code mit freundlicher Genehmigung von ndtreviv.

7

Verwendung dieser Code.

package playground 

    class User { 

     String name 
     static hasMany = [ posts : Post ] 

     static mapping = { 
      posts sort:'position' order:'desc'//order:'asc' 
     } 
    } 
+1

Danke Ich habe Sie upvoted, aber Reihenfolge: "asc" funktioniert nicht für mich, also habe ich es einfach weggelassen, weil der Standardwert asc ist. – dsharew

0

Antwort Owens hat mich von der Verwirrung ich in war, war ich auf die die Bestellung auf einer Beziehung zwischen den Nutzern (1) und Pfosten (viele) definiert versucht, aber Als ich die ersten Tests schrieb, scheiterten sie, da User.get (u.id) in derselben Sitzung war - und so gerade aus dem Cache gelesen wurde und sie in der Reihenfolge zurückkamen, in der ich nicht als erstes neu geschrieben hatte Ich hatte erwartet.

Ich schrieb dann den Test über zwei Sitzungen und niedrig und siehe in der zweiten Sitzung dieses Mal die Beiträge in desc Reihenfolge zurück.

Sie müssen also nur vorsichtig sein. Wenn Sie sich in derselben ursprünglichen Sitzung befinden, in der die Posts erstellt werden, müssen Sie User.get (u.id) .posts.sort() verwenden.

All diese kleinen Fehler, die nicht richtig verstehen, wie der Sitzungscache und die zugrundeliegende DB im Bereich derselben Sitzung/Transaktion arbeiten. macht manchmal dein Gehirn weh.

während wir die Dinge notieren - dies ist beim Integrationstest in 3.2.5 fehlerhaft, aber ich entdeckte einen Thread von Jeff und den Fix, der gegangen war. So ein Upgrade i 3.2.6 letzte Nacht Grails und dieser Test funktioniert nun

void "test query"() { 
    given:"a user and where query for users, and posts " 
    User u 

    when: "create a post for user " 
    User.withNewSession { session -> 
     u = new User(username: 'will') 
     u.save(flush: true, failOnError: true) 
     Post p1 = new Post(comment: [food: "bought coffee and cake "]) 
     Post p2 = new Post(comment: [dinner: "bought wine and dinner"]) 
     Post p3 = new Post(comment: [view: "spectacular view of lake and sunset"]) 
     u.addToPosts(p1) 
     u.addToPosts(p2) 
     u.addToPosts(p3) 
     u.save(flush: true) 
     if (u.hasErrors()) 
      println "error saving posts on user u : ${u.errors}" 


     def postList = User.get(u.id).posts 
     postList.each { println "query via user.list using same session > $it.dateCreated : $it.comment" } 

     Post.findAll().each { println "query via Post using same session > $it.dateCreated : $it.comment" } 
    } 
    //because still in same session it just returns the order from the 1st level cache - so force a 
    //new session and let the DB do the sort 
    def lookupPosts 
    User.withNewSession{ session -> 
     User uNew = User.get(1) 
     assert uNew 
     lookupPosts = uNew.posts 

     lookupPosts.each {println "query via user in new session > $it.dateCreated : $it.comment" } 
    } 



    then: " check post was added" 
    !u.hasErrors() 
    lookupPosts.size() == 3 
    lookupPosts[1].comment.dinner == "bought wine and dinner" 

}