Spring JPA:在同一查询接口上使用多个投影

4
我正在尝试使用Spring JPA的投影来过滤查询结果中的不必要数据。但是,我有多个投影需要在同一个接口方法上使用。
问题是,我正在尝试使用不同的返回对象从同一方法中查询数据,但Java不允许这样做。
查询是根据方法名自动生成的,因此我不能更改方法名。
除了创建新接口之外,是否有其他替代方案,因为我认为这很麻烦且不必要。
以下是我想要实现的示例代码:

自动生成的查询

public interface UserRepository extends CrudRepository<UserAccount, Long> {

    AuthenticateProjection getByUsername(String username);

    UserDetailsProjection getByUsername(String username);

}

投影

public interface AuthenticateProjection {

    @Value("#{target.username}")
    String getUsername();

    @Value("#{target.credentail.token}")
    String getHashPassword();
}

public interface UserDetailsProjection {

    @Value("#{target.username}")
    String getUsername();

    @Value("#{target.firstname}")
    String getFirstName();

    @Value("#{target.lastname}")
    String getLastName();
}

你为什么想要“过滤”信息——这是为了从控制器返回,还是为了内部使用? - chrylis -cautiouslyoptimistic-
@chrylis 它将返回给控制器 - XPLOT1ON
2个回答

7

我成功找到了如何在一个查询中使用多个投影的方法。

<T> T getByUsername(String username, Class<T> projection)

这使得方法调用者可以指定要应用于查询的投影类型。

为了进一步改进这个方法,使其更不容易出错,我创建了一个空接口,投影必须扩展该接口才能将类插入参数中。

public interface JPAProjection {
}

public interface UserRepository extends CrudRepository<UserAccount, Long> {
    <T extends JPAProjection > T getByUsername(String username, Class<? extends JPAProjection> projection);
}

投影接口

public interface UserDetailsProjection extends JPAProjection{
    @Value("#{target.username}")
    String getUsername();

    @Value("#{target.firstname}")
    String getFirstname();

    @Value("#{target.lastname}")
    String getLastname();
}

那么我可以通过以下方式调用查询方法:

getByUsername("...", UserDetailsProjection.class)

我尝试使用您的解决方案,但对我无效。在Eclipse控制台中,我看到一个错误:Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: from near line 1, column 9 [select from com.app.company.domain.organization.Organization as generatedAlias0 where generatedAlias0.deletedAt is null]。看一下“select”语句:没有任何列。也许你有同样的问题?似乎存储库没有接收到正确的投影类型.....有什么想法吗?非常感谢! - Andrea Bevilacqua
这很奇怪。我没有遇到任何问题。你能附上你的实现吗?可以用Pastebin吗?@AndreaBevilacqua - XPLOT1ON

3

只需在get(或例如find)和以大写字母开头的By之间添加内容即可。查询生成过程中会忽略此内容。

public interface UserRepository extends CrudRepository<UserAccount, Long> {

   AuthenticateProjection getByUsername(String username);

   UserDetailsProjection getAnotherByUsername(String username);

}

最佳答案!无需编写代码,您只需要编写要检索的数据“模式”,例如:getByUsername、getFullByUsername、getLightByUsername。 - Frédéric Nobre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接