替换spring-data页面的全部内容,同时保持分页信息

Jam*_*ron 5 spring spring-data spring-data-jpa spring-boot

使用spring-data-jpa并从表中获取数据,其中有大约十二列用于查询以查找特定行,然后是一个clob类型的有效负载列,其中包含编组到java对象中的实际数据被退回.

实体对象非常粗略

@Entity
@Table(name = "Person")

public class Person {
    @Column(name="PERSON_ID", length=45) @Id private String personId;
    @Column(name="NAME", length=45) private String name;
    @Column(name="ADDRESS", length=45) private String address;
    @Column(name="PAYLOAD") @Lob private String payload;

    //Bunch of other stuff
} 
Run Code Online (Sandbox Code Playgroud)

(这种方法是否合理是一个不同讨论的主题)

clob列会导致性能受到大量查询的影响......

为了改善一些事情,我创建了一个单独的实体对象...没有负载......

@Entity
@Table(name = "Person")

public class NotQuiteAWholePerson {
    @Column(name="PERSON_ID", length=45) @Id private String personId;
    @Column(name="NAME", length=45) private String name;
    @Column(name="ADDRESS", length=45) private String address;

    //Bunch of other stuff
} 
Run Code Online (Sandbox Code Playgroud)

这让我得到一个NotQuiteAPerson页面......然后我通过personIds查询完整人物对象的页面.

希望是在原始查询中不使用有效负载,这可能会在支持表的一小部分上过滤数据,当我正在检索要查看的对象的当前页面时,我只关心自己的有效负载...一个小得多的块.

所以我想要将原始返回的NotQuiteAWholePerson页面的内容映射到我的人员列表,同时保持所有的分页信息不变,但是map方法只需要一个将迭代NotQuiteAWholePerson对象的Converter ......这不太适合我想做的事情.

有没有明智的方法来实现这一目标?


关于为什么现有的map()不够用@itsallas的补充说明..

PageImpl :: map有

@Override
public <S> Page<S> map(Converter<? super T, ? extends S> converter) {
    return new PageImpl<S>(getConvertedContent(converter), pageable, total);
}
Run Code Online (Sandbox Code Playgroud)

Chunk :: getConvertedContent有

protected <S> List<S> getConvertedContent(Converter<? super T, ? extends S> converter) {

    Assert.notNull(converter, "Converter must not be null!");

    List<S> result = new ArrayList<S>(content.size());

    for (T element : this) {
        result.add(converter.convert(element));
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

因此,原始的内容列表将通过...和应用提供的转换方法进行迭代,以构建要插入到现有Pageable中的新内容列表.

但是我不能单独将NotQuiteAWholePerson转换为Person,因为我不能简单地构造有效载荷......我可以,如果我在转换中通过Id向每个Person调用数据库...但是单独调用是不理想的从表现的角度来看......

获得我的NotQuiteAWholePerson页面之后,我正在查询整个人员列表...通过Id ...在一个电话中...现在我正在寻找一种方法来替换整个内容列表...而不是间断地,如同现有的map()确实如此,但只是简单的替换.

这个特殊的用例也可以帮助将有效负载(json)更适当地保存在像Mongo这样的NoSql数据存储中...而不是sql数据存储clob ......

希望能更好地澄清一下.

小智 3

您可以使用 Spring Data JPA 功能完全避免该问题。

最明智的方法是使用 Spring Data JPA投影,它有很好的广泛文档。

例如,您首先需要确保属性的延迟获取,这可以通过属性本身的注释来实现。

IE :

@Basic(fetch = FetchType.LAZY)  @Column(name="PAYLOAD") @Lob private String payload;
Run Code Online (Sandbox Code Playgroud)

或者通过获取/加载图表,这在存储库级别得到了很好的支持

您需要以一种或另一种方式定义它,因为从文档中逐字获取:

查询执行引擎在运行时为返回的每个元素创建该接口的代理实例,并将对公开方法的调用转发给目标对象。

然后您可以像这样定义投影:

interface NotQuiteAWholePerson {
    String getPersonId();
    String getName();
    String getAddress();

    //Bunch of other stuff
}
Run Code Online (Sandbox Code Playgroud)

并将查询方法添加到您的存储库:

interface PersonRepository extends Repository<Person, String> {

    Page<NotQuiteAWholePerson> findAll(Pageable pageable);
    // or its dynamic equivalent
    <T> Page<T> findAll(Pageable pageable, Class<T>);
}
Run Code Online (Sandbox Code Playgroud)

给定相同的可分页,一页投影将引用同一会话中的相同实体。

如果您出于某种原因无法使用投影(即,如果您使用 JPA < 2.1 或投影之前的 Spring Data JPA 版本),您可以使用所需的列和关系定义显式 JPQL 查询,或者保留 2-entity设置。然后,您可以手动或(最好)使用您选择的对象映射框架将Persons 和NotQuiteAWholePersons 映射到类。PersonDTO

注意。:有多种方法可以使用和设置惰性/渴望关系。这涵盖了更多细节