Hibernate HQL:找不到查询的实体

时间:2015-12-08 10:52:57

标签: hibernate entity hql

它花了一天时间尝试解决这个问题,但它仍然没有成功。 我有测试实体

public class Test {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "duration", nullable = false)
private int duration;
@Column(name = "test_name", nullable = false, unique = true)
private String testName;
@Column(name = "archived", nullable = false)
private boolean archived;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "test", fetch = FetchType.EAGER)
private Set<Question> questions;
@ManyToMany(mappedBy = "tests")
private Set<User> users;

测试实体问题集,这样问题实体答案集

我编写了HQL查询来进行测试:

 @NamedQuery(name = "getCurrentTestById",
            query = "SELECT test From Result result JOIN result.test test JOIN result.user user " +
                    "JOIN test.questions question JOIN question.answers answer " +
                    "WHERE test.id = :testId AND user.id = :userId " +
                    "AND result.permission.id = :permissionId AND question.isArchived = false AND answer.isArchived = false")

我的DAO

    public Test getCurrentTest(long id, long testId, long permissionId){
    Query query = em.createNamedQuery("getCurrentTestById");
    query.setParameter("userId", id);
    query.setParameter("testId", testId);
    query.setParameter("permissionId", permissionId);
    return (Test)query.getSingleResult();
}

所以,在我将任何问题或答案设置为“已存档”之前,一切正常。 我仍然可以获得所有这些内容,即使它们已归档。此外,如果我将当前测试的所有问题\答案标记为已存档 - 我将获得例外:找不到查询的实体

2 个答案:

答案 0 :(得分:2)

我认为我们在这里对Hibernate概念有些误解。

首先,在使用Hibernate时,您无法使用查询从实体中获取确定集合中的几行,换句话说,当您检索获取其中一个实体的实体时, ; s集合,即使使用查询专门从集合中删除那些不需要的记录,也将检索此集合中存在的所有记录

执行此操作的一种方法是使用Hibernate's filtering,但这需要对映射和配置进行一些更改,因此我不会对此方法做出更多解释,而是会使用您的实际配置来解释如何解决您的问题。

在你所展示的查询中,你只是告诉Hibernate你想要一个测试记录,它的问题和答案都没有存档,所以无论如何Hibernate都能够确定Test实体内的集合也应该通过WHERE子句进行过滤。

您可以从测试中获取未归档的所有问题的一种方法是直接从Test实体中选择Question对象,在其中创建所需的WHERE,如下所示:

SELECT question FROM Result result 
  JOIN result.test test 
  JOIN result.user user
  JOIN test.questions question
  JOIN question.answers answer
 WHERE test.id = :testId
   AND user.id = :userId
   AND result.permission.id = :permissionId 
   AND question.isArchived = false 
   AND answer.isArchived = false

在此示例中,您将收到一个来自测试的问题集合,这些问题也会被WHERE子句过滤。

但是,如果您真的需要为您的逻辑使用Test实体,您可以在Test实体中创建一个get方法,它将返回一组未归档的Questions,然后使用这个方法在你的逻辑中:

   public Set<Question> getQuestionsNotArchived() {
        Set<Question> notArchivedQuestions = new HashSet<>();
        for (Question question : questions) {
            if (!question.isArchived()) {
                 notArchivedQuestions.add(question);
            }
        }
        return notArchivedQuestions;
   }

这是一个非常好的方法来过滤Hibernate集合,我个人经常使用它。

有了这个,我们就解决了你所描述的第一个问题,因为现在你可以使用Questions集合的过滤值获得一个Test实体。

现在,对于第二个问题,找不到查询的实体,它非常简单:因为你正在使用Query类的getSingleResult()而引发错误,所以如果它没有从您的查询中找到任何结果,它将抛出异常。你没有得到任何结果的原因是因为你在WHERE子句中明确说明你只想要至少有一个没有存档的问题/答案的测试,并且你也说过,它只会在你标记所有的时候发生问题/答案已归档,因此错误是非常期待的,因为您实际上没有任何问题/答案没有存档。

希望通过这些解释,你可以解决你的问题,祝你好运!

答案 1 :(得分:2)

我发现这样做的最佳解决方案是使用Test实体进行保存(如果您不想创建包装器或多个查询)并编写 NATIVE SQL查询:< / p>

@NamedNativeQuery(name = "getCurrentTestById",
            query = "SELECT t.id as tId, t.test_name, t.duration, q.id as qId, " +
                    "q.question, q.is_multichoice, q.is_open, a.id as aId, a.answer_text  FROM result r " +
                    "JOIN test t ON r.test_id = t.id " +
                    "JOIN user u ON r.user_id = u.id " +
                    "JOIN question q ON t.id = q.test_id JOIN answer a ON q.id = a.question_id " +
                    "WHERE t.id = :testId AND u.id = :userId AND r.permission = :permissionId " +
                    "AND q.archived = false AND a.archived = false")