2012-03-26 203 views
2

我有一個簡單的雙向一對多映射,如下所示,其中擁有指定的默認排序順序。但是,排序順序似乎沒有得到應用?我正在使用Grails v2.0.1(我現在已經用v1.3.7複製了這個例子)。Grails:一對多關係無法正常工作的排序順序

package playground 

class User { 

    String name 

    static hasMany = [ posts : Post ] 

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

package playground 

class Post { 

    int position = 1 
    String message 

    static belongsTo = [ user : User ] 
} 

這是我使用行使它集成測試代碼...

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}" 
    } 

請把我從我的痛苦,這大概是明顯的東西但我看不到它!謝謝。

+0

這種排序只適用於從數據庫中拉出時的情況。也許嘗試user.refresh()在你的for循環之前,看看這是真的嗎?這不是一個修復,但它可能解釋不同的順序。 – Igor 2012-03-26 17:44:39

+0

這或取得一個新的參考將其與User.findByName(「鮑勃」)來強制往返,或許不應該需要,但是可以添加一個沖洗:真正的節省以及 – 2012-03-26 17:46:52

+1

有趣。 flush:true不起作用,但用戶。刷新()做了。奇怪的是,如果你從數據庫中調用用戶(def User UserUser = User.get(user.id);)然後遍歷帖子它仍然不按排序順序 - 可能是因爲它已經獲得從緩存中(儘管添加flush:true在那裏也不起作用)。這不是我用集成測試看到的第一個奇怪現象......令人擔憂。 – ndtreviv 2012-03-27 12:07:13

回答

0

如果您使用列表而不是Set(默認),框架將爲您維護訂單。

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

或者也許是一個SortedSet來保留有用的設置行爲... – ndtreviv 2012-03-27 14:35:20

+0

@ j4y - 使用List將保持插入順序。然而,我正在尋找的是能夠在域對象ala [grails docs]的域中聲明排序順序(http://grails.org/doc/2.0.1/guide/GORM.html#defaultSortOrder ) – owenrh 2012-03-27 21:19:42

1

原來,這是一種奇怪的邊緣情況行爲,這實際上是測試寫入方式的結果。基本上,所有事情都發生在單個Hibernate session/txn的範圍內(參見上面的對話)。因此,測試將取回它剛剛創建的對象圖(使用亂序Set),而不是從數據庫中獲取數據。

如果您強制執行單獨的事務,那麼您將得到您正在查找的行爲,並且'按順序'按預期工作。例如。

​​

代碼提供ndtreviv。

7

使用此代碼:

package playground 

    class User { 

     String name 
     static hasMany = [ posts : Post ] 

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

謝謝我已經upvoted你,但順序:「asc」不適合我,所以我只是把它離開了,因爲默認是asc。 – dsharew 2014-10-30 08:19:04

0

歐文的回答讓我走出困惑我是在我試圖在對用戶(1)和職位(許多)之間的關係定義的排序,但當我寫了最初的測試時,他們失敗了,因爲使用User.get(u.id)是在同一個會話 - 所以只是讀出緩存,他們回來的順序我寫了不是最新的第一個作爲我曾預料過。

然後我重寫了兩個會話和低的測試,並且在第二次會話中看到這次按desc順序返回了帖子。

所以你只需要小心。如果你在創建帖子的原始會話中,那麼你必須使用User.get(u.id).posts.sort()。

所有這些小問題都無法正確理解會話緩存和底層DB如何在同一會話/事務的範圍內工作。有時會讓你的大腦疼痛。

,同時我們注意到的事情 - 這個差錯在集成測試3.2.5,但我發現傑夫線程,並且已經走了修復。所以我升級到grails 3.2.6昨晚,這個測試現在可以運行

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" 

}