如何使Groovy / Grails返回一个对象列表而不是一个对象列表?

时间:2012-06-20 23:56:05

标签: grails collections groovy closures collect

我有一个这样的课程:

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

当我写:

Foo.getAll()

我得到了Foo这样的对象列表:

[ Foo1, Foo2, Foo3 ]

当我写:

Foo.getAll().bars

我得到一个Bar对象列表的列表,如下所示:

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

但我想要的是一个Bar对象的唯一列表,如下所示:

[ Bar1, Bar2, Bar3, Bar4 ]

我的最终目标是在上面的列表中有一个唯一的Bar对象ID列表,如下所示:

[ 1, 2, 3, 4 ]

我尝试了collect方法的各种变体,我也试过spread operator,但我没有运气。

3 个答案:

答案 0 :(得分:8)

对于通用的groovy类(即非GORM类),David认为使用flattenunique是最好的方法是正确的。

在您的示例中,看起来您在多对多关系中使用GORM域对象(否则您不需要唯一性约束)。

对于域类,您最好使用HQL或条件一步完成此操作。另一个优点是为它生成的SQL效率更高。

这是用于获取与多对多关系中的任何Bar相关的唯一Foo ID的HQL:

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

这个标准如下:

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

一个"问题"使用这种方法的方法是单元测试(可能永远不会)和Criteria queries with join table projections are broken in 2.0.4 unit tests不支持HQL。因此,围绕此代码的任何测试都需要进行模拟或使用集成测试。

答案 1 :(得分:4)

可能有更好的方法,但您可以使用flattenunique

类似的东西:

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

编辑:
我刚刚重新阅读,看到你最后是一个ID列表,而不是Bars。如您所建议,您将使用collect{ it.id }来获取ID。出于性能原因,我会在列表唯一之前这样做。

答案 2 :(得分:4)

Collection#collectMany方法与调用collect然后调用flatten的方法相同。要获取条形码ID列表,您可以执行以下操作:

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

{ it.bars*.id }闭包返回一个列表,其中包含一个Foo的Bars的ID(我喜欢这些占位符名称hehe),然后collectMany将这些列表连接成一个列表。如果您需要ID是唯一的(可能Bar可以属于多个Foo),您可以在该表达式中添加.unique():)