【问题标题】:Hibernate list distinct from 4 tables与 4 个表不同的休眠列表
【发布时间】:2015-11-08 23:38:54
【问题描述】:

我们正在将一些遗留代码从 sql 重写为带有 h​​ibernate 的 gorm。 我偶然发现了一个问题——我们有 4 个不同的表,映射到 4 个域类。它们中的每一个都有一个名称相同的列/属性。 考虑以下(实际上很愚蠢)表进行简化:

+-------------------+      +---------------------------+
| id | name |  role |      | id | position |    role   |
+-------------------+      +---------------------------+
|  1 | John | admin |      |  1 |  manager |     admin |
|  2 |  Bob |  user |      |  2 | sysadmin | superuser |
+-------------------+      +---------------------------+

从这些表/类中,我需要提取所有不同角色。 使用 SQL,这可以通过 union 轻松完成:

SELECT role FROM Table1 UNION SELECT role FROM Table2 GROUP BY role

返回所需结果:[admin, user, superuser]

现在我想知道,如何使用 gorm/hibernate 来做到这一点。一种可能的解决方案是使用以下两个标准:

first = Table1.createCriteria().list {
  projections {
    distinct "role"
  }
}
second = Table2.createCriteria().list {
  projections {
    distinct "role"
  }
}

然后遍历它们并过滤重复项。然而,这不是很有效,几乎是原始查询时间的两倍(给定 4 个表,有效地导致 4 个查询)。 那么,最有效(时间和资源)的解决方案是什么?

// 更新(响应@Emmanuel)

我无法控制数据库。我的访问是只读的。更可怕的是,表中总共有大约 400 万行。这些数据会定期更新,每分钟都会添加新行,因此无法在某处创建新表。

【问题讨论】:

    标签: hibernate grails grails-orm


    【解决方案1】:

    GORM/Hibernate 不支持 UNION 查询。我建议对表进行规范化,以便列(例如角色)位于单个表中,而其他列通过外键引用它。使用您的表格示例:

    +-----------------+
    + id | role       +
    +-----------------+
    +  1 | admin      +
    +  2 | user       +
    +  3 | superuser  +
    +-----------------+
    
    +-------------------+
    + id | name |  role +
    +-------------------+
    +  1 | John |   1   +
    +  2 |  Bob |   2   +
    +-------------------+
    
    +---------------------------+
    + id | position |    role   +
    +---------------------------+
    +  1 |  manager |     1     +
    +  2 | sysadmin |     3     +
    +---------------------------+
    

    然后,当然,您可以简单地查询新的域类。

    【讨论】:

    • 好吧,我会说你是在一块石头和一个坚硬的地方之间。 GORM 不会提供任何帮助。但是,它确实提供了一种获取 Hibernate 会话的方法,这意味着您可以执行 SQL:def roles = AnyDomainClassReallyAnyWillDo.withNewSession { session -> session.createSQLQuery('SELECT role FROM Table1 UNION SELECT role FROM Table2 GROUP BY role').list() }
    • 当我去这里询问时,我内心深处知道这将是唯一的解决方案。但是,仍然有一点希望 - 我会等待一些其他建议。如果没有别的,我会接受这个作为答案。谢谢
    【解决方案2】:

    如果您不想使用 HQL,可以这样做:

    List<Role> list = Table1.createCriteria().list {
      projections {
        distinct "role"
        property "role"
      }
    }
    list = Table2.createCriteria().list {
      not{
        'in'('role', list)
      }
      projections {
        distinct "role"
        property "role"
      }
    }
    

    【讨论】:

    • 这行不通,我已经尝试过类似的方法。 list 在第二次查询后变得太大,然后第三次查询失败 - 列表过滤器有一个限制,1k 或 10k 或类似的东西
    • 哦,是的,抱歉,您只需要收集属性角色。尝试更正。
    • 你不懂。问题出在'in'('role', list) 中,如果list 太大(在我的情况下是这样),则会失败。
    • 第一个条件只为您提供 Table1 拥有的独特角色。
    猜你喜欢
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2015-04-24
    • 2015-05-23
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多