6

我有这样的课:

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 ]

我尝试了收集方法的变体,也尝试了传播运算符,但我没有任何运气。

4

3 回答 3

8

对于通用的 groovy 类(即非 GORM 类),David 是正确的,flatten并且unique是最好的方法。

但是,在您的示例中,您似乎在多对多关系中使用 GORM 域对象(否则您将不需要唯一性约束)。

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

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

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

标准如下:

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

使用这种方法的一个“问题”是 HQL 在单元测试中不受支持(并且可能永远不会支持),并且带有连接表投影的 Criteria 查询在 2.0.4 单元测试中被破坏。因此,围绕此代码的任何测试都需要模拟或使用集成测试。

于 2012-06-21T02:15:46.073 回答
4

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

就像是:

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

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

于 2012-06-21T00:14:10.383 回答
4

有一种方法与调用thenCollection#collectMany的工作方式相同。要获取 Bar ID 列表,您可以执行以下操作:collectflatten

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

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

于 2012-06-21T00:26:49.563 回答