问题描述
花了一天的时间来解决这个问题,但仍然没有成功。
我有测试实体:
It spent a day trying solve this problem however it's still not successful.I have Test entity :
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查询以进行测试:
I wrote HQL query to get test:
@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();
}
所以,一切正常,直到我将任何问题或答案设置为已存档 。 即使它们已存档,我仍然可以全部获取。此外,如果我将所有用于当前测试的问题集答案都标记为已存档-我将获得例外:找不到要查询的实体
So, everything is OK until i set any Question or Answer as "archived". I am still getting all of them, even if they are archived. Moreover, if i will mark all Set of questions\answers for current test as archived - i will get exception : no entity found for query
推荐答案
我认为我们在这里对Hibernate概念有误解。
I think we have some misunderstood of the Hibernate concept here.
首先,使用Hibernate时无法获取使用查询从某个实体的确定集合中仅获取了几行,换句话说,当您检索一个实体以获取其某个集合时,即使使用查询来检索该集合中存在的所有记录,专门从集合中删除那些不需要的记录。
First of all, when using Hibernate you can't fetch only a few rows from a determined collection from an entity using a query, in other words, when you retrieve a entity fetching one of it's collection, all the records present in this collection will also be retrieved, even using a query to specifically remove those undesired records from the collection.
一种方法是使用,但这需要对映射和配置进行一些更改,因此我不会有关此方法的更多说明,我将使用您的实际配置解释如何解决问题的合理方法。
One way to do this is using the Hibernate's filtering, but that would require a few changes in your mapping and configurations, so I will not make more explanations about this approach, instead I will use your actual configuration to explain what can be done to resolve your problem.
在查询中,您显示的只是告诉Hibernate您想要的测试记录是问题和答案是没有存档,因此无论如何,Hibernate都可以确定Test实体内部的集合也应通过WHERE子句进行过滤。
In the query you have showed you are only telling Hibernate that you want a Test record which it's questions and answers are not archived, so by any means Hibernate would be able to determine that the collection inside the Test entity should also be filtered by the WHERE clause.
一种获取所有内容的方式测试中未归档的问题将直接从测试实体中选择要在其中放置所需WHERE的问题对象,例如:
One way you can get all the Questions from a Test that are not archived would be doing selecting directly the Question objects from the Test entity making the desired WHERE inside of it, like the following:
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子句进行过滤。
In this example you will receive a collection of Questions from a Test that are also getting filtered by your WHERE clause.
但是,如果您确实需要使用测试实体,您可以在Test实体中创建一个get方法,该方法将返回未归档的一组Questions,然后在逻辑中使用该方法的结果:
However, if you are really in need to use the Test entity for your logic, you can just create a get method in the Test entity that will the return a set of Questions that are not archived, and then use the results from this method in your logic:
public Set<Question> getQuestionsNotArchived() {
Set<Question> notArchivedQuestions = new HashSet<>();
for (Question question : questions) {
if (!question.isArchived()) {
notArchivedQuestions.add(question);
}
}
return notArchivedQuestions;
}
这是过滤Hibernate集合的一种非常好的方法,我个人非常喜欢使用此方法
It is a perfectly fine approach to filter Hibernate collections, I personally use this quite often.
有了这个,我们可以解决您描述的第一个问题,因为现在您可以获得带有Questions集合的过滤值的Test实体。
With this we solve the first problem you described, since now you can get a Test entity with the filtered values of the Questions collection.
现在,对于第二个问题,未找到要查询的实体,这很简单:由于使用了Query类中的getSingleResult(),因此引发了错误,因此如果找不到查询结果,它将引发异常。之所以无法获得任何结果,是因为您在WHERE子句中明确表示只希望拥有至少一个未归档的问题/答案的测试,并且也正如您所说的那样,只有在标记所有问题/答案已存档,因此错误很出乎意料,因为实际上您没有任何未存档问题/答案的测试。
Now, for the second problem, the no entity found for query, it's quite simple: The error is being raised because you are using the getSingleResult() from Query class, so it will throw an exception if it do not find any result from your query. The reason you are not getting any result if because you are explicit saying in you WHERE clause that you want only Tests which have at least one Question/Answer that is not archived, and as you also said, it only happen when you mark all the Question/Answer as archived, so the error is quite expected, since you in fact do not have any Test with Question/Answer not archived.
希望有这样的解释,您可以解决您的问题,祝您好运!
Hope with this explanations you can resolve your problems, good luck!
这篇关于Hibernate HQL:找不到要查询的实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!