JPQL JOIN查询

时间:2013-11-01 19:19:19

标签: hibernate join jpql spring-data

我试图使用连接创建一个非常简单的JPQL,但我没有成功。我希望在给定用户ID的情况下获取用户的最新登录日期。我正在使用Spring Data JPA + Hibernate。

我有一个MySQL数据库,其中包含表Activity:

@Table(name = "activity")
@SuppressWarnings("serial")
public class Activity implements Serializable {
@Id
@GeneratedValue
private Long id;

@Column(name = "date", insertable = true, nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date date;

@Column(insertable = true, name = "organization_id", nullable = true, updatable = true, unique = false)
@Basic(optional = true)
private Long organizationId;

@Column(insertable = true, name = "operation", nullable = false, updatable = true, unique = false)
@Basic(optional = false)
private String operation;

//getters and setters
}

它包含许多其他表,包括LoginAttempt:

@Table(name = "login_attempt")
@SuppressWarnings("serial")
public class LoginAttempt implements Serializable{

@Id
@GeneratedValue
private Long id;

@OneToOne(fetch = FetchType.EAGER, optional = false)
@Basic(optional = false)
@JoinColumn(name = "activity_id", insertable = true, nullable = false, unique = false, updatable = false)
private Activity activity;

@Column(insertable = true, name = "user_id", nullable = true, updatable = true, unique = false)
@Basic(optional = true)
private Long userId;

@Column(insertable = true, name = "user_email", nullable = true, updatable = true, unique = false)
@Basic(optional = true)
private String userEmail;

@Column(insertable = true, name = "login_successful", nullable = false, updatable = true, unique = false)
@Basic(optional = false)
private boolean loginSuccessful;

//getters and setters
}

所有其他表使用名为" activity_id"。

的列引用Activity

这是我的DAO,有一个方法和@Query注释。

public interface MyDAO extends JpaRepository<Activity, Long> {

@Query("SELECT a FROM Activity a, LoginAttempt la JOIN a.id la WHERE la.user_email = (:userId) AND a.date = (SELECT MAX(a.date))")
public Activity findMostRecentLoginForUser(@Param("userId") Long userId);

}

当我在@Query中有一个简单的select all语句时,它正常工作,所以我正确地连接到数据库并且能够将所有内容都恢复。我最初在查询中遇到了很多验证错误,但现在我得到了以下内容(部分堆栈跟踪)。

Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract com.domain.Activity com.dao.MyDAO.findMostRecentLoginForUser(java.lang.Long)!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:97)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:66)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.fromQueryAnnotation(SimpleJpaQuery.java:169)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:114)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:160)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:290)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:158)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:162)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:44)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 44 more
Caused by: java.lang.NullPointerException
at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:393)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:3645)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3431)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3309)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:706)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:562)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:299)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:247)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:250)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:138)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:105)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:168)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:221)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:199)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1778)
at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:291)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
at com.sun.proxy.$Proxy33.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:91)
... 54 more

我的大脑被炸了,我无法理解我读过的任何一个例子。任何帮助表示赞赏。感谢。

1 个答案:

答案 0 :(得分:0)

您的查询格式错误 - 其子查询未指定从中选择的内容。此外,由于您有LoginAttemptActivity的直接引用,因此您无需进行任何显式连接。尝试这样的事情(未经测试):

SELECT la.activity FROM LoginAttempt la 
WHERE la.user_email = :userId
AND la.activity.date = (SELECT MAX(la2.activity.date) FROM LoginAttempt la2
                        WHERE la2.user_email = :userId)

子查询选择给定用户的最新日期。外部查询为给定用户选择Activity,其日期是子查询的结果。