在Spring Data JPA Repository中使用EntityGraph进行过滤

3
我可以帮您翻译成中文。这段内容是关于编程的,讲述了一个包含一对多关系的“Listing”表和“ListingAttachment”的表。在整个应用程序中,每个表/实体都有“deleteFlag”,每个存储库只能使用“deleteFlag” 0来获取数据。因此,基本上我们不会删除任何数据,只是将“deleteFlag”标记为1。
以下是我的实体结构:

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

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


}

ListingRepository.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);

}

使用EntityGraph,我们可以轻松获取OneToMany实体。但问题是如何过滤或应用条件在Many相关实体上。
例如,在我的情况下,我应该获取deleteFlag为0的Listing及其所有附件(ListingAttachments),这些附件也必须具有deleteFlag为0。使用上面存储库中显示的EntityGraph,它会获取所有附件,而不考虑deleteFlag。是否有任何方法可以根据deleteFlag过滤附件?
1个回答

7

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

在没有 EntityGraph 的 JPA 2.0 中,如果想要使用 FetchType.LAZY (默认) 或 FetchType.EAGER 加载关系,则必须在实体上定义这种方式,并且该模式始终被使用。

通过 EntityGraph,可以按查询定义属性和(子-)图。

EntityGraph 不用于过滤元素。

如果您想查找未标记为删除(delete flag = 0)且至少有一个未标记为删除的 ListingAttachmentListings,则可以使用 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);

}

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

以上示例将返回所有未标记为已删除且至少有一个未标记为已删除的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")

1
有一个更正 ... 对于未标记为删除且没有ListingAttachments的清单,我们必须在where子句中添加a is null。 因此查询将是@Query("SELECT l FROM Listing l LEFT OUTER JOIN l.listingAttachments a WHERE l.id = (:id) and l.deleteFlag = 0 and (a is null OR a.deleteFlag = 0)") - hemu
如果@Query定义了自己的连接,那么@EntityGraph将添加一个额外的不必要的连接,而该连接在查询中根本没有使用。另一方面,如果没有@EntityGraph,则实体将逐个获取。我正在努力解决这种情况。 - mangusta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接