我使用springboot为购物站点创建了一个层次结构或树形结构。我的问题是寻找特定产品及其父项时如何查询这样的结构:
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数据库
类别实体
@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);
}
}
答案 0 :(得分:0)
您可以使用递归查询来选择给定类别的父项。
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.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));
}
}
}
请注意,这已在H2和PostgreSQL数据库上进行了测试。您可能需要根据使用的实际数据库修改本机查询。
PostgreSQL关于它如何工作的出色文档,请参见: