它花了一天时间尝试解决这个问题,但它仍然没有成功。 我有测试实体:
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();
}
所以,在我将任何问题或答案设置为“已存档”之前,一切正常。 我仍然可以获得所有这些内容,即使它们已归档。此外,如果我将当前测试的所有问题\答案标记为已存档 - 我将获得例外:找不到查询的实体
答案 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")