2012-06-20 33 views
6

Tôi có một lớp học như thế này:Làm thế nào để Groovy/Grails trả về một danh sách các đối tượng thay vì một danh sách các đối tượng?

class Foo { 
    static hasMany = [bars: Bar] 
} 

Khi tôi viết:

Foo.getAll() 

tôi nhận được một danh sách các Foo đối tượng như thế này:

[ Foo1, Foo2, Foo3 ] 

Khi tôi viết:

Foo.getAll().bars 

tôi nhận được một danh sách liệt kê của Bar đối tượng như thế này:

[ [ Bar1, Bar2 ], [ Bar2, Bar3 ], [ Bar1, Bar4 ] ] 

Nhưng những gì tôi muốn là một danh sách duy nhất của Bar đối tượng như thế này:

[ Bar1, Bar2, Bar3, Bar4 ] 

mục tiêu cuối cùng của tôi là để có một độc đáo danh sách các id của đối tượng Bar trong danh sách ở trên, như sau:

[ 1, 2, 3, 4 ] 

Tôi đã thử các biến thể của collect phương pháp và tôi cũng đã thử các spread operator nhưng tôi không có bất kỳ may mắn.

Trả lời

8

Đối với các lớp học chung (các lớp không phải GORM), David là đúng sử dụng flattenunique là cách tốt nhất để thực hiện.

Trong ví dụ của bạn, có vẻ như bạn đang sử dụng các đối tượng tên miền GORM trong mối quan hệ nhiều-nhiều (nếu không bạn sẽ không cần ràng buộc duy nhất).

Đối với một lớp miền, tốt nhất bạn nên sử dụng HQL hoặc tiêu chí để thực hiện việc này trong một bước. Một lợi thế nữa là SQL được tạo ra cho nó hiệu quả hơn nhiều.

Đây là HQL để nhận được Bar id duy nhất có liên quan đến bất kỳ Foo trong một mối quan hệ nhiều-nhiều:

Bar.executeQuery("select distinct b.id from Foo f join f.bars b") 

Tiêu chí này sẽ như thế nào:

Foo.withCriteria { 
    bars { 
     projections { 
      distinct("id") 
     } 
    } 
} 

Một "vấn đề" với việc sử dụng loại phương pháp này là HQL không được hỗ trợ trong các bài kiểm tra đơn vị (và có khả năng sẽ không bao giờ) và Criteria queries with join table projections are broken in 2.0.4 unit tests. Vì vậy, bất kỳ thử nghiệm nào xung quanh mã này sẽ cần phải được chế nhạo hoặc sử dụng thử nghiệm tích hợp.

+1

+1 Điều này rất có thể là cách tốt nhất để thực hiện trong trường hợp này :) – epidemian

+0

Vâng, đã đồng ý :) – David

+0

Cảm ơn tất cả các bạn đã trả lời câu hỏi của bạn. Chúc các bạn có thể upvote tất cả các bạn :) Tôi muốn tránh HQL, nhưng có gần như hoàn thành nhiệm vụ của tôi bằng cách sử dụng tiêu chí, bây giờ tôi tìm thấy pagination được ... phiền hà. Nếu tôi không thể nhận được phân trang để chơi tốt đẹp bằng cách sử dụng tiêu chí tôi sẽ phải đi đến HQL tôi nghĩ. – ubiquibacon

4

Có thể có cách tốt hơn, nhưng bạn có thể sử dụng flattenunique.

Cái gì như:

def allBars = Foo.getAll().bars.flatten().unique()

Edit:
Tôi vừa mới đọc lại và thấy rằng bạn đang theo đuổi một danh sách các ID cuối cùng, không phải là Bars. Như bạn đã đề xuất, bạn sẽ sử dụng collect{ it.id } để nhận ID. Tôi sẽ làm điều đó trước khi đưa ra danh sách duy nhất, vì lý do hiệu suất.

4

Có phương thức Collection#collectMany hoạt động theo cách tương tự như gọi collect và sau đó flatten. Để có được danh sách các ID Bar, bạn có thể làm:

def barIds = Foo.getAll().collectMany { it.bars*.id } 

Các { it.bars*.id } đóng cửa trả về một danh sách với các ID của Bars của một Foo (tôi yêu các tên giữ chỗ hehe), và sau đó collectMany concatenates những danh sách vào một danh sách duy nhất. Nếu bạn cần các ID là duy nhất (có thể một Bar có thể thuộc về nhiều hơn một Foo), bạn có thể thêm một số .unique() vào biểu thức đó :)

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