2010-10-11 24 views
7

Tôi đang sử dụng NimbleShiro cho các khuôn khổ bảo mật của mình và tôi vừa mới gặp phải lỗi GORM. Thật vậy:GORM createCriteria và danh sách không trả về cùng kết quả: tôi có thể làm gì?

User.createCriteria().list { 
    maxResults 10 
} 

lợi nhuận 10 người trong khi User.list(max: 10) lợi nhuận 9 người đã!

Sau khi điều tra thêm, tôi phát hiện ra rằng createCriterialợi nhuận gấp đôi so với cùng sử dụng (admin) vì quản trị có 2 vai trò !!! (Tôi không nói đùa).

Dường như bất kỳ người dùng với hơn 1 vai trò sẽ được trả lại gấp đôi trong createCriteria cuộc gọi và User.list sẽ trở lại max-1 trường hợp (tức là 9 người dùng thay vì 10 users)

workaround Những gì tôi có thể sử dụng để có 10 người dùng duy nhất được trả về?

Điều này rất khó chịu vì tôi không có cách nào để sử dụng phân trang một cách chính xác.


lớp miền của tôi là:

class UserBase { 
    String username 
    static belongsTo = [Role, Group] 
    static hasMany = [roles: Role, groups: Group] 
    static fetchMode = [roles: 'eager', groups: 'eager'] 
    static mapping = { 
    roles cache: true, 
    cascade: 'none', 
    cache usage: 'read-write', include: 'all' 
    } 
} 

class User extends UserBase { 
    static mapping = {cache: 'read-write'} 
} 

class Role { 
    static hasMany = [users: UserBase, groups: Group] 
    static belongsTo = [Group] 
    static mapping = { cache usage: 'read-write', include: 'all' 
    users cache: true 
    groups cache: true 
    } 
} 
+0

Triển khai của bạn cuối cùng là gì? Bởi vì tôi có cùng một vấn đề. Cảm ơn rất nhiều –

Trả lời

4

Ít súc tích và rõ ràng, nhưng sử dụng một truy vấn HQL dường như một cách để giải quyết vấn đề này. Như được mô tả trong phần Grails documentation (phần executeQuery), các tham số phân trang có thể được thêm vào như các tham số bổ sung cho executeQuery.

User.executeQuery("select distinct user from User user", [max: 2, offset: 2]) 
+0

Cảm ơn rất nhiều. Nó hoạt động !! Bạn có biết nếu có một vấn đề JIRA đầy lỗi này? – fabien7474

+0

Giải thích chi tiết về lý do tại sao listDistinct chỉ lọc ra các bản sao trong bộ nhớ có thể tìm thấy ở đây trong Hibernate FAQ: http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Hibernate_does_not_return_distinct_results_for_a_query_with_outer_join_fetching_enabled_for_a_collection_even_if_I_use_the_distinct_keyword. – Ruben

0

Bạn có thể sử dụng

User.createCriteria().listDistinct { 
    maxResults 10 
} 
+0

Hầu hết hoạt động:) ListDistinct sẽ trả lại 9 người dùng thay vì 10 người dùng (loại bỏ người dùng bị trùng lặp). Nhưng làm thế nào tôi có thể sử dụng pagination như thế với params offset ví dụ. – fabien7474

+0

Điều này có thể hữu ích: http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html –

+0

Vấn đề với phép chiếu riêng biệt là bạn chỉ giữ 'cột' hoặc thuộc tính mà trên đó sự khác biệt là được chỉ định. – Ruben

3

cách này bạn vẫn có thể sử dụng các tiêu chuẩn và vượt qua trong danh sách/pagination PARAMATERS

User.createCriteria().listDistinct { 
    maxResults(params.max as int) 
    firstResult(params.offset as int) 
    order(params.order, "asc") 
} 
+0

không chỉ cung cấp thông số pagination, về việc có một PagedResultList thực sự với tập hợp thuộc tính totalCount ... – codewandler

1

Cả hai giải pháp được cung cấp ở đây bởi Ruben và Aaron vẫn không "hoàn toàn" làm việc cho pagination vì trở lại object (từ executeQuery() và listDistinct) là một ArrayList (với tối đa đối tượng trong nó), và không phải PagedResultList với thuộc tính totalCount được điền như tôi mong đợi cho việc hỗ trợ "hoàn toàn" phân trang.

Giả sử ví dụ phức tạp hơn một chút trong đó: a. giả sử Vai trò có thuộc tính rolename bổ sung VÀ b. chúng tôi chỉ muốn trả về các đối tượng User khác nhau với Role.rolename chứa một chuỗi "a" (lưu ý rằng Người dùng có thể có nhiều Vai trò với rolename có chứa chuỗi "a")

Để thực hiện điều này với 2 truy vấn Tôi sẽ phải làm một việc như sau:

// First get the *unique* ids of Users (as list returns duplicates by 
// default) matching the Role.rolename containing a string "a" criteria 
def idList = User.createCriteria().list { 
    roles { 
    ilike("rolename", "%a%") 
    } 
    projections { 
    distinct ("id") 
    } 
} 

if(idList){ 
    // Then get the PagedResultList for all of those unique ids 
    PagedResultList resultList = 
    User.createCriteria().list(offset:"5", max:"5"){ 
     or { 
     idList.each { 
      idEq(it) 
     } 
     }  
     order ("username", "asc") 
    } 
} 

Điều này có vẻ không hiệu quả.

Câu hỏi: có cách nào để thực hiện cả hai điều trên với một câu lệnh GORM/HQL?

+0

bạn có thể sử dụng id trong id "id" thay vì vòng lặp và idEq (nó) –

2

EDIT: Tìm thấy cách để có được cả hai! Hoàn toàn sẽ sử dụng nó bây giờ

http://www.intelligrape.com/blog/tag/pagedresultlist/

If you call createCriteria().list() like this 
def result=SampleDomain.createCriteria().list(max:params.max, offset:params.offset){ 
// multiple/complex restrictions 
    maxResults(params.max) 
    firstResult(params.offset) 
} // Return type is PagedResultList 
println result 
println result.totalCount 

Bạn sẽ có tất cả thông tin bạn cần trong một định dạng PagedResultList tốt đẹp!

/EDIT

Đáng tiếc là tôi không biết làm thế nào để có được một sự kết hợp của kết quả đầy đủ VÀ max/bù đắp pagination tập con trong cuộc gọi tương tự. (Bất cứ ai có thể khai sáng về điều đó?)

Tuy nhiên, tôi có thể nói theo một cách mà tôi đã sử dụng với thành công để có được phân trang làm việc nói chung trong grails.

def numResults = YourDomain.withCriteria() { 
    like(searchField, searchValue) 
    order(sort, order) 
    projections { 
     rowCount() 
    } 
} 

def resultList = YourDomain.withCriteria() { 
    like(searchField, searchValue) 
    order(sort, order) 
    maxResults max as int 
    firstResult offset as int 
} 

Đó là ví dụ về nội dung tôi đang sử dụng để thiết lập và chạy trang. Như KoK đã nói ở trên, tôi vẫn thua lỗ cho một tuyên bố nguyên tử duy nhất cho cả hai kết quả. Tôi nhận ra rằng câu trả lời của tôi ít nhiều giống với KoK bây giờ, xin lỗi, nhưng tôi nghĩ rằng nó đáng để chỉ ra rằng rowCount() trong các dự báo là rõ ràng hơn một chút để đọc và tôi chưa có đặc quyền nhận xét:/

Cuối cùng: Đây là chén thánh (không có ý định chơi chữ) của các tham chiếu sử dụng tiêu chuẩn grails hibernate; đánh dấu nó;) http://www.grails.org/doc/1.3.x/ref/Domain%20Classes/createCriteria.html

Các vấn đề liên quan