Spring Boot - 搜索类别树

时间:2017-03-03 17:05:32

标签: java spring postgresql spring-boot repository

我正在编写基本上是广告服务的Spring Boot应用程序。在数据库中(我使用PostgreSQL方言)我存储类别树。每个类别都包含对其直接父级的引用。每个广告都分配了他的类别,并且出于问题的原因,您只能将广告分配给叶子类别。

下面的图片捕捉结构。

Category tree

现在我需要从数据库中检索特定类别的广告。但是,我想说我想要检索所有类别E的广告。这意味着我想要检索属于E类子类的广告,但不一定是直接的孩子。在这种情况下,我想检索G,H,I和J类别的广告,因为它们都是叶子,它们都是E类的孩子。

如何通过Spring存储库实现它?以下是此示例的简化实体类。

类别...

@Entity
@Table(name = "categories")
public class Category {

    @Id
    @Column(name = "cat_id")
    private int id;

    @Column(name = "cat_name", length = 50, nullable = false, unique = true)
    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "cat_parent", referencedColumnName = "cat_id", nullable = false)
    private Category parent;

    ...
}

...和广告。

@Entity
@Table(name = "advertisements")
public class Advertisement {

    @Id
    @Column(name = "adv_id")
    private long id;

    @Column(name = "adv_title", length = 100, nullable = false)
    private String title;

    @Column(name = "adv_description", length = 5000, nullable = false)
    private String description;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "adv_category", referencedColumnName = "cat_id", nullable = false)
    private Category category;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "adv_owner", referencedColumnName = "user_id", nullable = false)
    private User owner;

    ...
}

1 个答案:

答案 0 :(得分:0)

执行此操作可能不是最优雅的方式,但您可以先收集类别包,然后使用 in 中的查询广告存储库,该结果仅将结果限制为这些类别中的广告。

首先将父/子关联的另一端添加到Category对象(如果它已经不存在),并创建一个方法,返回包含该类别和所有子项的集合(不仅仅是直接的)像:

@JoinColumn(name = "cat_parent")
@OneToMany
Set<Category> children;
... 
public Set<Category> collectLeafChildren() { 
   Set<Category> results = new HashSet<>(); 
   if (children.isEmpty()) { 
      results.add(this); 
   } else { 
      children.forEach(child -> { 
        results.addAll(child.collectLeafChildren()); 
      }); 
   } 
   return results; 
}

然后为Advertisement存储库创建一个新方法,该方法返回给定类别集的所有广告,如:

List<Advertisement> findByCategoryIn(Set<Category> categories);

并使用那些:

Set<Category> categories = category.collectLeafChildren();
List<Advertisement> advertisementRepository.findByCategoryIn(categories);