【问题标题】:Select subset of the list contained in an entity选择实体中包含的列表的子集
【发布时间】:2015-12-17 12:15:47
【问题描述】:

假设我想获取 ID 小于 10 的 MyEntity 的所有行。该实体包含 Another 实体的列表。我希望这个列表只能由listAnother 的一个子集获取。该子集仅包含 Another,其中包含的 user 是特定的。

在 SQL 中基本上是这样的:

SELECT * FROM myentity m
LEFT JOIN another a
ON m.idTable=a.my_entity
AND a.user = "test1"
WHERE m.idTable < 10;

但是我没能把这个查询翻译成 jpql。

我的实体是这样的:

@Entity
public class MyEntity implements Serializable {    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int idTable;

    @OneToMany(mappedBy = "myEntity")
    private List<Another> listAnother;

}

@Entity
public class Another implements Serializable {    
    @Id
    private int idAnother;

    // bi-directional many-to-one association to Thethread
    @ManyToOne(fetch = FetchType.LAZY)
    private MyEntity myEntity;

    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}

@Entity
public class User implements Serializable {

    @Id
    private String username;
}

在 jpa 中我可以这样做:

SELECT m FROM MyEntity where m.idTable < 10;

然后对于我从这个列表中得到的每个实体调用这个:

SELECT a FROM Another Where a.user.username=:'test' AND a.myEntity=:entity;

但是,我想在一个查询中一次完成所有操作。我可以用标准来做到这一点吗?我没有花时间学习它,但如果可能的话,我会的。

【问题讨论】:

    标签: java jpa criteria jpql


    【解决方案1】:

    JPQL 和 Critaria API 在您可以表达的内容方面是相同的。 JPQL 可以实现的功能可以通过 Criteria 实现,反之亦然。

    使用 JPQL,您可以通过以下方式简单地将 2 个查询合并为一个:

    SELECT a FROM Another a Where a.user.username=:test AND a.myEntity.idTable < 10
    

    您可以使用点表示法 (.) 来连接查询中的多个实体,前提是关系是 X 对一的。如果你有 X 对多的关系,你需要使用 JPQL JOIN,这不是很复杂。 (LEFT) JOIN 示例:

    SELECT m FROM MyEntity m LEFT JOIN m.listAnother a Where a.user.username=:test AND m.idTable < 10
    

    结果当然不相等 - 在第一种情况下,您将获得另一个实体的列表,您可以通过 a.myEntity 获得 MyEntity,在第二种情况下,您将获得 MyEntity 的列表,它们都至少有一个另一个实体给定用户

    【讨论】:

    • 等一下,我正在重新阅读您的答案,最后它说“所有这些都至少有一个具有给定用户的另一个实体”。我想要的是 MyEntity ,它有一个大小为 1 或 0 的列表,其中包含 if size 1 :另一个具有给定用户的列表。
    • 编辑了我的评论*,但我想我找到了方法。因此,当我确定并发布您的评论时,我会让您编辑您的评论,我会接受您的回答。
    • 使用纯 JPA 无法获得过滤集合的实体 - 您总是在 X 对多映射中获得所有相关实体。如果您想过滤,您需要发出另一个查询,正如您在问题中所写的那样。使用特定于实现的 API 可能会实现您想要的,但即使这样也可能导致意外行为。另见对话here
    • 非常感谢您的宝贵时间。这不会让事情变慢吗?假设我的原始返回列表大小为 100。这对数据库进行了 100 次额外调用。也许我可以看看 jdbc 是否可以解决问题。
    • 顺便说一句,我让它工作了,但这有点奇怪。如果您有兴趣:stackoverflow.com/questions/32705101/…
    【解决方案2】:

    在休眠中,您可以使用过滤器和 FilterJoinTable。 Here 你可以阅读如何做到这一点。类似问题已解决here

    【讨论】:

    • 哦,我在标签中放入了休眠,但我的意思是放入标准。我不使用休眠。我非常抱歉。不过我会看看你的线索。
    【解决方案3】:

    您需要扩展用于检查用户名 (a.user.username=:'test') 的逻辑,该逻辑用于任何事物和用户之间的多对一关系,方法是将其提升到 myEntity 和然后也将它用于一对多关系 -

     SELECT m FROM MyEntity where m.idTable < 10 and (m.listAnother.user.username=:'test')
    

    现在不需要连接条件“m.listAnother.myEntity=:entity”,因为在我们的查询中,我们从特定的 myEntity 开始,然后向下移动到 listAnother.user.username。

    我没有表定义来自己尝试这个查询,确切的 SQL 可能需要一些调整 - 但从逻辑上讲,它应该像我上面展示的那样工作,即就像你加入另一个用户的方式,和你一样的方式只需遍历子 listAnother 即可将 MyEntity 与 Another 加入。

    【讨论】:

    • 那行不通。如果用户不在该列表中,我只想在列表中包含另一个具有用户“测试”的实体(假设每个列表只有一个)或 myentity 的空列表。
    猜你喜欢
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 2017-03-23
    相关资源
    最近更新 更多