在 Spring Data JPA 存储库中使用 EntityGraph 进行过滤

hem*_*emu 3 java spring jpa spring-data-jpa spring-boot

我有一张Listing与 具有一对多关系的表ListingAttachment。现在在整个应用程序中,每个表/实体都有deleteFlag,每个存储库应该只获取deleteFlag0 的数据。所以基本上,我们不会删除任何数据,只是将 deleteFlag 标记为 1。

以下是我的实体结构:

清单.java

@Entity
public class Listing {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    String title;

    String description;

    @OneToMany(mappedBy = "listing", cascade={CascadeType.ALL})
    private Set<ListingAttachment> listingAttachments;

    private int deleteFlag; 

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getDeleteFlag() {
        return deleteFlag;
    }

    public void setDeleteFlag(int deleteFlag) {
        this.deleteFlag = deleteFlag;
    }

    public Set<ListingAttachment> getListingAttachments() {
        return listingAttachments;
    }

    public void setListingAttachments(Set<ListingAttachment> listingAttachments) {
        this.listingAttachments = listingAttachments;
    }

    public ListingAttachment addListingAttachment(ListingAttachment listingAttachment) {
        getListingAttachments().add(listingAttachment);
        listingAttachment.setListing(this);
        return listingAttachment;
    }

    public ListingAttachment removeListingAttachment(ListingAttachment listingAttachment) {
        getListingAttachments().remove(listingAttachment);
        listingAttachment.setListing(null);
        return listingAttachment;
    }
}
Run Code Online (Sandbox Code Playgroud)

清单附件.java

@Entity
public class ListingAttachment {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    String fileName;

    @ManyToOne
    @JoinColumn(name = "LISTING_ID")    
    private Listing listing;

    private int deleteFlag;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public Listing getListing() {
        return listing;
    }

    public void setListing(Listing listing) {
        this.listing = listing;
    }

    public int getDeleteFlag() {
        return deleteFlag;
    }

    public void setDeleteFlag(int deleteFlag) {
        this.deleteFlag = deleteFlag;
    }


}
Run Code Online (Sandbox Code Playgroud)

列表存储库.java

public interface ListingRepository extends JpaRepository<Listing, Long> {

        @EntityGraph(attributePaths = { "listingAttachments" }) 
        @Query("SELECT l FROM Listing l WHERE l.id = (:id) and deleteFlag = 0")
        public ListingfindOneWithImagesAndAttachments(@Param("id") Long id);

}
Run Code Online (Sandbox Code Playgroud)

使用EntityGraph我们可以轻松获取 OneToMany 实体。但问题是如何在Many相关实体上过滤或应用条件。

例如,在我的例子中,我应该使用Listing0deleteFlag及其所有附件(ListingAttachments)来获取,而后者也必须具有deleteFlag0。EntityGraph如上面的存储库所示,它会获取所有附件,而不管deleteFlag. 有什么方法可以根据 过滤附件deleteFlag吗?

and*_*dih 7

EntityGraph定义了应该获取(急切或惰性)实体的哪些属性或(子)图,而不必在实体本身上定义它们。

在 JPA 2.0(没有 EntityGraph)中,您必须在实体上定义是否要使用FetchType.LAZY(默认)或FetchType.EAGER加载关系,并且始终使用此模式。

使用EntityGraph,您可以定义每个查询的属性和(子)图。

EntityGraph不用于过滤元素。

如果您想查找哪些Listings未标记为已删除 ( delete flag = 0) 并且其中至少有一个ListingAttachment未标记为已删除,您可以使用FETCH JOIN

public interface ListingRepository extends JpaRepository<Listing, Long> {

    @EntityGraph(attributePaths = { "listingAttachments" }) 
    @Query("SELECT l FROM Listing l JOIN l.listingAttachments a 
        WHERE l.id = (:id) and l.deleteFlag = 0 and a.deleteFlag = 0")
    public Listing findOneWithImagesAndAttachments(@Param("id") Long id);

}
Run Code Online (Sandbox Code Playgroud)

您需要加入 ,ListingAttachments因为您无法deleteFlag使用集合在 JPA 查询中直接取消引用listingAttachments

上面的示例返回所有未标记为已删除的列表,并且至少有一个未标记为已删除的 ListingAttachment。

如果您想返回未标记为已删除但可能没有 ListingAttachments 的列表,则必须将其更改为LEFT OUTER JOIN

@Query("SELECT l FROM Listing l 
   LEFT OUTER JOIN  l.listingAttachments a 
   WHERE l.id = (:id) and l.deleteFlag = 0 and a.deleteFlag = 0")
Run Code Online (Sandbox Code Playgroud)