具有多个不同 @Id 列的 JPA 查询

问题描述 投票:0回答:1

问题

为了使我的代码更清晰,我想引入一个通用存储库,每个存储库都可以扩展它,从而减少每个存储库中必须拥有的代码。问题是,不同类的 ID 不同。在一个(参见下面的示例)上它是

id
,在另一个上是
randomNumber
,在另一个上甚至可能是 @EmbeddedId。我想在存储库中有一个派生(或非派生)查询,通过 id 获取 One。

首选解决方案

我想象有这样的事情:

public interface IUniversalRepository<T, K>{
    @Query("select t from # {#entityName} where @id = ?1")
    public T findById(K id);
}

示例代码

(这不起作用,因为在“设置”中找不到属性
id

public interface IUniversalRepository<T, K>{
    //should return the object with the id, reagardless of the column name
    public T findById(K id);
}
// two example classes with different @Id fields
public class TaxRate {

    @Id
    @Column()
    private Integer id;

    ...
}

public class Settings{

    @Id
    @Column() //cannot rename this column because it has to be named exactly as it is for backup reason
    private String randomNumber;

    ...
}
// the Repository would be used like this
public interface TaxRateRepository extends IUniversalRepository<TaxRate, Integer> {
}

public interface SettingsRepository extends IUniversalRepository<TaxRate, String> {
}

很高兴收到建议。

java spring spring-data-jpa spring-data
1个回答
3
投票

通过“id 查询”检索 JPA 实体的想法并不像您想象的那么好,主要问题是速度要慢得多,特别是当您在事务中多次访问同一实体时:如果刷新模式设置为 AUTO (这实际上是合理的默认值)Hibernate 需要在执行 JPQL 查询之前执行脏检查并将更改刷新到数据库中,此外,Hibernate 不保证通过“id 查询”检索的实体实际上不是过时的 - 如果实体已经存在在持久化上下文中,Hibernate 基本上会忽略数据库数据。

通过 id 检索实体的最佳方法是调用

EntityManager#find(java.lang.Class<T>, java.lang.Object)
方法,该方法又会备份
CrudRepository#findById
方法,因此,您的
findByIdAndType(K id, String type)
实际上应该如下所示:

default Optional<T> findByIdAndType(K id, String type) {
    return findById(id)
            .filter(e -> Objects.equals(e.getType(), type));
}

但是,在 JQPL 查询中放置某种

id
占位符的愿望并没有那么糟糕 - 它的应用程序之一可以在分页查询中保持顺序稳定性。我建议您将相应的CR提交到
spring-data
项目。

© www.soinside.com 2019 - 2024. All rights reserved.