使用EntityGraph时无法在Spring中实现正确的分页行为

to94eoyn  于 2023-05-21  发布在  Spring
关注(0)|答案(1)|浏览(147)

在过去的几天里,我一直在为简单的事情而挣扎(我认为它应该是简单的)。我想达到的目标:
创建一个端点,它将响应产品实体页面。产品实体需要有类别和图片元数据,它们是父/子记录。
为了实现上述目标,我在实体上实现了NamedEntityGraph,它的工作原理是获取所有需要的相关实体,避免N+1。当我试图从存储库中获取产品页面并使用提到的EntityGraph时,就会发生这个问题。问题是我用错误的数据检索页面。示例:
我有5个产品要回收。当页面大小设置为2时,我得到:

"pageable": {
        "sort": {
            "empty": false,
            "unsorted": false,
            "sorted": true
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 2,
        "unpaged": false,
        "paged": true
    },
    "last": true,
    "totalPages": 1,
    "totalElements": 1,
    "first": true,
    "size": 2,
    "number": 0,
    "sort": {
        "empty": false,
        "unsorted": false,
        "sorted": true
    },
    "numberOfElements": 1,
    "empty": false

据我所知,这个问题来自查询中连接其他表。我一直在寻找答案,但什么也没找到。在Spring项目中如何处理?
实体

@Indexed
@Entity(name = "product")
@Table(name = "product")
@NoArgsConstructor
@Getter
@Setter
@AllArgsConstructor
@NamedEntityGraph(
        name = Product.WITH_CATEGORY,
        attributeNodes = {
                @NamedAttributeNode(value = "category"),
                @NamedAttributeNode(value = "mainPictureMetadata"),
                @NamedAttributeNode(value = "picturesMetadata")
        }
)
public class Product {

    public static final String WITH_CATEGORY = "graph.product.category";

    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Column(name = "id", nullable = false, updatable = false)
    @JdbcTypeCode(SqlTypes.VARCHAR)
    @Setter(AccessLevel.NONE)
    private UUID id;

    @Embedded
    private EntityAudit auditData;

    @Length(max = 512, min = 1)
    @FullTextField
    private String name;

    @Length(max = 5120)
    @Nullable
    @FullTextField
    private String description;

    @Column(nullable = false)
    @GenericField
    private Boolean published;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id", referencedColumnName = "id")
    @IndexedEmbedded
    private Category category;

    @OneToOne
    @JoinColumn(name = "main_picture_metadata_id")
    private PictureMetadata mainPictureMetadata;

    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
    private Set<PictureMetadata> picturesMetadata;
}

回购:

public interface ProductRepo {

    Product save(Product product);
    
    @EntityGraph(value = Product.WITH_CATEGORY)
    Page<Product> findAll(Pageable pageable);

}

售后服务:

public Page<Product> selectProductPage(int pageNumber) {
        final Pageable pageable = PageRequest.of(pageNumber, 2, Sort.by("auditData.createdDate").descending());
                return repo.findAll(pageable);
          }
pcww981p

pcww981p1#

因此,我实施的解决方案非常简单有效。这是两个查询-第一个仅分页选择id,然后第二个不分页但打开实体图的id获取:

public interface ProductRepo {

    @EntityGraph(value = Product.WITH_CATEGORY)
    List<Product> findByIdIn(Set<UUID> ids);
    
    @Query("SELECT p.id FROM product p")
    Page<UUID> findAllIds(Pageable pageable);
}

及服务方式:

public Page<Product> selectProductPage(int pageNumber) {
        final Pageable pageable = PageRequest.of(pageNumber, 2, Sort.by("auditData.createdDate").descending());
        final Page<UUID> pageOfIds = repo.findAllIds(pageable);
        final Set<UUID> ids = Set.copyOf(pageOfIds.getContent());
        final List<Product> products = repo.findByIdIn(ids);
        return new PageImpl<>(products, pageable, pageOfIds.getTotalElements());
    }

相关问题