如何使用 JPA 实现“轻实体”版本?

Val*_*kyi 6 java mysql spring spring-data-jpa

有一个“完整实体”类:

@Entity(name = "vacancy_dec_to_words")
public class VacancyDescriptionToWords {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @JoinColumn(name = "vacancy_description_id")
    @ManyToOne(cascade = CascadeType.ALL)
    private VacancyDescription vacancyDescription;

    @JoinColumn(name = "words_id")
    @ManyToOne
    private Words words;

    @Column(name = "qty")
    private int qty;

    @Column(name = "create_date")
    private Date date;

    //...getters and setters
Run Code Online (Sandbox Code Playgroud)

在某些方法中,我只需要使用此数据库中的 2 列:word_idqty

我尝试以下方式:

预测 https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#projections

public interface QtyWords {
    Long getWords();
    Integer getQty();
}
Run Code Online (Sandbox Code Playgroud)

Jpa存储库:

*查询,我使用测试过并且它可行,我使用他JpaRepository

@Repository
public interface SmallVDTWRepository extends JpaRepository<VacancyDescriptionToWords, Long> {

@Query(nativeQuery = true,
        value = "SELECT sum(qty), words_id FROM vacancy_desc_to_words WHERE vacancy_description_id IN (" +
                "SELECT id FROM vacancy_description WHERE vacancy_id IN (" +
                "SELECT id FROM vacancy WHERE explorer_id = :exp))" +
                "GROUP BY words_id")
List<QtyWords> getDistinctWordsByExplorer(@Param("exp") long exp);
}
Run Code Online (Sandbox Code Playgroud)

但是当我获得实体列表时,我得到了一些有趣的结果:

    List<QtyWords> list = vdtwService.getByExplorerId(72);
Run Code Online (Sandbox Code Playgroud)

我没有得到任何例外,但我有未知对象的列表。该对象包含我需要的数据(qtywords_id),但我无法从他那里获取它们。

在此输入图像描述

我可以使用这个方法(Projection)来实现这个任务吗?一般来说,在这种情况下如何正确实现“Light Entity”?

Ale*_*kov 5

Spring提供了两种可用于限制数据获取的机制。

预测

通过设置您想要获取的确切属性,投影可以帮助您减少从数据库检索的数据。

例子:

@Entity
class Person {
    @Id UUID id;
    String firstname, lastname;
    @OneToOne
    Address address;
}

@Entity
static class Address {
    @Id UUID id;
    String zipCode, city, street;
}

interface NamesOnly {
    String getFirstname();
    String getLastname();
}

@Repository
interface PersonRepository extends Repository<Person, UUID> {
    Collection<NamesOnly> findByLastname(String lastname);
}
Run Code Online (Sandbox Code Playgroud)

实体图

EntityGraph通过设置需要获取的确切相关实体,注释可以帮助您减少对数据库的查询量。

例子:

@Entity
@NamedEntityGraph(name = "GroupInfo.detail", attributeNodes = @NamedAttributeNode("members"))
public class GroupInfo {
    @Id UUID id;
    @ManyToMany //default fetch mode is lazy.
    List<GroupMember> members = new ArrayList<GroupMember>();
}

@Repository
public interface GroupRepository extends CrudRepository<GroupInfo, String> {

    @EntityGraph(value = "GroupInfo.detail", type = EntityGraphType.LOAD)
    GroupInfo getByGroupName(String name); //Despite of GroupInfo.members has FetchType = LAZY, it will be fetched because of using EntityGraph
}
Run Code Online (Sandbox Code Playgroud)

有两种类型EntityGraph

  1. EntityGraphType.LOAD- 用于指定实体图,实体图的属性节点指定的属性将被视为FetchType.EAGER,未指定的属性将根据其指定或默认进行处理FetchType
  2. EntityGraphType.FETCH- 用于指定实体图,实体图的属性节点指定的属性被视为FetchType.EAGER,未指定的属性被视为FetchType.LAZY

PS:还请记住,您可以设置延迟获取类型:@ManyToOne(fetch = FetchType.LAZY)并且在获取父实体时,JPA 将不会获取子实体。