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

时间:2018-08-02 14:02:35

标签: spring spring-boot spring-data-jpa spring-data

使用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
} 

(这种方法是否明智是另一个讨论的主题)

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
} 

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

希望是,在原始查询中不使用有效负载(可以过滤大量支持表上的数据)时,我只在获取要查看的对象的当前页面时才关心有效负载...一块小得多。

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

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


@itsallas的其他说明,说明为什么现有的map()无法满足要求。

PageImpl :: map具有

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

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;
}

因此,原始目录列表通过...进行迭代,并应用提供的convert方法,以构建新的目录列表,以将其插入现有的Pageable中。

但是,我不能将NotQuiteAWholePerson单独转换为Person,因为我不能简单地构造有效负载...好吧,如果我通过转换中的ID通过每个ID为每个Person调用了DB,则可以...但是可以单独调用从性能角度来看并不理想...

在获取我的NotQuiteAWholePerson页面后,我正在一次呼叫中查询ID的整个人员列表...现在,我正在寻找一种替代整个内容列表的方法...就像现有的map()一样,只是简单地替换。

这个特殊的用例也将有助于将json的有效负载更合适地持久存储在像Mongo这样的NoSql数据存储中...而不是sql数据存储clob ...

希望可以更好地阐明这一点。

1 个答案:

答案 0 :(得分:2)

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

最明智的方法是使用Spring Data JPA projections,该文档具有广泛的文档。

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

即:

@Basic(fetch = FetchType.LAZY)  @Column(name="PAYLOAD") @Lob private String payload;

或通过neatly supported at repository-level的“获取/加载图”。

您需要以一种或另一种方式进行定义,因为从文档中逐字逐句地得出结论:

  

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

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

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

    //Bunch of other stuff
}

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

interface PersonRepository extends Repository<Person, String> {

    Page<NotQuiteAWholePerson> findAll(Pageable pageable);
    // or its dynamic equivalent
    <T> Page<T> findAll(Pageable pageable, Class<T>);
}

鉴于相同的可分页,一页投影将指向同一会话中的相同实体。

如果由于某种原因不能使用投影(即,如果您使用JPA <2.1或在投影之前使用Spring Data JPA版本),则可以使用所需的列和关系定义一个显式的JPQL查询,或者保留2实体设置。然后,您可以手动或(最好)使用所选的对象映射框架将PersonNotQuiteAWholePerson映射到PersonDTO类。

NB。 :有多种使用和设置懒惰/渴望关系的方法。 This covers more in detail