我正在编写基本上是广告服务的Spring Boot应用程序。在数据库中(我使用PostgreSQL方言)我存储类别树。每个类别都包含对其直接父级的引用。每个广告都分配了他的类别,并且出于问题的原因,您只能将广告分配给叶子类别。
下面的图片捕捉结构。
现在我需要从数据库中检索特定类别的广告。但是,我想说我想要检索所有类别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;
...
}
答案 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);