Java 如何查询深度未定义的层次分类树实体
我使用springboot为购物网站创建了一个层次结构或树结构。我的问题是,在查找特定产品及其父产品时,如何查询这种结构:Java 如何查询深度未定义的层次分类树实体,java,spring-boot,tree,Java,Spring Boot,Tree,我使用springboot为购物网站创建了一个层次结构或树结构。我的问题是,在查找特定产品及其父产品时,如何查询这种结构: id, category_name, parent_id '1', 'Electronics', NULL '2', 'Gaming', NULL '3', 'Home Audio', '1' '4', 'Console', '2' '5', 'Sony', '4' '6', 'Kar
id, category_name, parent_id
'1', 'Electronics', NULL
'2', 'Gaming', NULL
'3', 'Home Audio', '1'
'4', 'Console', '2'
'5', 'Sony', '4'
'6', 'Karaoke', '3'
这就是我所做的,关于我需要在实体上做什么来实现这个结构的任何指针,以及我如何查询它,即
还需要注意的是,我正在使用postgres数据库
public class CategoryService {
@Autowired
private CategoryRepository categoryRepository;
public void addCategory(Category category) {
categoryRepository.save(category);
}
}
public class ProductService {
@Autowired
private ProductRepository productRepository;
public void addProduct(Product product) {
productRepository.save(product);
}
}
@Entity
@Table(name = "categories")
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String categoryName;
@ManyToOne
@JoinColumn(name = "parent_id")
private Category parent;
@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<Category> children = new ArrayList<Category>();
// Getter and setter removed for readability
}
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Version
@Column(name = "version")
private Integer version;
private String name;
private int quantity;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "products_categories", joinColumns = {
@JoinColumn(name = "product_id", referencedColumnName = "id") }, inverseJoinColumns = {
@JoinColumn(name = "category_id", referencedColumnName = "id") })
private List<Category> categories;
// getters and setter omitted for readability
}
产品服务
public class CategoryService {
@Autowired
private CategoryRepository categoryRepository;
public void addCategory(Category category) {
categoryRepository.save(category);
}
}
public class ProductService {
@Autowired
private ProductRepository productRepository;
public void addProduct(Product product) {
productRepository.save(product);
}
}
可以使用递归查询选择给定类别的父级
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface CategoryRepository extends JpaRepository<Category, Long> {
@Query(
value = "WITH RECURSIVE ancestors(id, parent_id, category_name, lvl) AS ("
+ " SELECT cat.id, cat.parent_id, cat.category_name, 1 AS lvl "
+ " FROM categories cat "
+ " WHERE cat.id = :categoryId "
+ " UNION ALL "
+ " SELECT parent.id, parent.parent_id, parent.category_name, child.lvl + 1 AS lvl "
+ " FROM categories parent "
+ " JOIN ancestors child "
+ " ON parent.id = child.parent_id "
+ " )"
+ "SELECT category_name from ancestors ORDER BY lvl DESC"
, nativeQuery = true)
List<String> findAncestry(@Param("categoryId") Long categoryId);
}
import org.springframework.data.jpa.repository.JpaRepository;
导入org.springframework.data.jpa.repository.Query;
导入org.springframework.data.repository.query.Param;
导入java.util.List;
公共接口类别repository扩展了JpaRepository{
@质疑(
value=“递归祖先(id、父项id、类别名称、lvl)为(”
+“选择cat.id、cat.parent\u id、cat.category\u name、1作为lvl”
+“来自类别cat”
+“其中cat.id=:categoryId”
+“全民联合”
+选择parent.id、parent.parent\u id、parent.category\u name、child.lvl+1作为lvl
+“来自父类别”
+“加入祖先的孩子”
+“ON parent.id=child.parent\u id”
+ " )"
+“按lvl DESC从订单中选择类别名称”
,nativeQuery=true)
列出findAncestry(@Param(“categoryId”)长categoryId);
}
以下是创建类别层次结构并对其进行查询的测试:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class HierarchyTest {
@Autowired
CategoryRepository categoryRepository;
@Test
public void testCategoryRepository() {
String[] electronicsCategoryNames = {"Electronics", "Home Audio", "Karaoke"};
String[] gamingCategoryNames = {"Gaming", "Console", "Sony"};
Category karaoke = createCategories(electronicsCategoryNames);
Category sony = createCategories(gamingCategoryNames);
findAncestry(karaoke, electronicsCategoryNames);
findAncestry(sony, gamingCategoryNames);
}
Category createCategories(String[] categoryNames) {
Category parent = null;
for (String categoryName : categoryNames) {
Category category = new Category();
category.setCategoryName(categoryName);
category.setParent(parent);
parent = categoryRepository.save(category);
}
Assert.assertNotNull("category.id", parent.getId());
return parent;
}
void findAncestry(Category category, String[] categoryNames) {
List<String> ancestry = categoryRepository.findAncestry(category.getId());
Assert.assertEquals("ancestry.size", categoryNames.length, ancestry.size());
for (int i = 0; i < categoryNames.length; i++) {
Assert.assertEquals("ancestor " + i, categoryNames[i], ancestry.get(i));
}
}
}
import org.junit.Assert;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.boot.test.context.SpringBootTest;
导入org.springframework.test.context.junit4.SpringRunner;
导入java.util.List;
@RunWith(SpringRunner.class)
@春靴测试
公共类层次结构测试{
@自动连线
分类报告分类报告;
@试验
public void testCategoryRepository(){
字符串[]electronicsCategoryNames={“电子”、“家庭音频”、“卡拉OK”};
字符串[]gamingCategoryNames={“Gaming”、“Console”、“Sony”};
类别卡拉OK=创建类别(电子分类名称);
类别索尼=创建类别(gamingCategoryNames);
findAncestry(卡拉OK、电子姓名);
findAncestry(索尼、gamingCategoryNames);
}
Category createCategories(字符串[]categoryNames){
类别父项=null;
for(字符串categoryName:categoryNames){
类别=新类别();
category.setCategoryName(categoryName);
类别。setParent(父级);
父项=categoryRepository.save(类别);
}
Assert.assertNotNull(“category.id”,parent.getId());
返回父母;
}
void findAncestry(类别,字符串[]类别名称){
List祖先=categoryRepository.findAncestry(category.getId());
Assert.assertEquals(“祖先.size”,categoryNames.length,祖先.size());
for(int i=0;i
注意,这是在H2和PostgreSQL数据库上测试的。您可能需要根据正在使用的实际数据库修改本机查询
PostgreSQL提供了关于如何工作的优秀文档,请参见:
从SQL的角度,检查
connectbypreor
子句。我正在使用spring.jpa.hibernate.ddl-auto=create从这些实体创建数据库。答案似乎在问题中。关于你发布的代码,有什么具体的问题吗?当我使用它时,代码没有创建那个结构,所以当我尝试创建类别并将它们链接到产品时。好吧,你没有发布试图创建那个结构的代码,那么我们如何帮助呢?我如何修改查询以便在postgres中使用