TreeGrid 是否支持没有 parent/child 关系的对象?
Does TreeGrid support objects without parent/child relationships?
我正在尝试使用 Vaadin TreeGrid
.
编写一个将呈现“任务”树的应用程序
需要注意的一件非常重要的事情是树节点类型不包含对父节点或任何子节点的引用。相反,一个单独的类型包含 parent/child 关系,引用树节点类型的项目的唯一 ID。
这两种类型分别存储在各自的数据库表中。数据本身是从 MS Excel 文件中提取的(不要问为什么)并插入到数据库中,应用程序利用该数据库访问数据。
为了更直观地呈现:
TaskMaster(树节点类型):
@Entity
public class TaskMaster extends AbstractEntity {
private String internalTaskID;
private String name;
private TaskType type;
// other fields
...
}
TaskRelationship(parent/child 关系):
@Entity
public class TaskRelationship extends AbstractEntity {
private String taskView;
private String parentTaskID;
private String childTaskID;
// other fields
...
}
我写了 @Repository
和 @Service
类 以方便根据需要检索信息。
我不知道如何让网格加载和显示代表任务树的节点层次结构。我查看了 Vaadin 示例,并创建了一个数据提供程序来尝试加载此数据,但无济于事。它仅加载根节点,不加载任何其他内容。
我想知道当节点对象包含对父子节点的引用时,树状网格是否只知道如何处理层次关系。 我的对象不这样做。 相反,我尝试在服务和数据提供程序中设置逻辑 类 以“获取”所需内容。显然那是行不通的。或者我错过了一些非常微妙的东西。
下面是代表我努力的一些代码。
任务主数据提供者:
public class TaskMasterDataProvider
extends AbstractBackEndHierarchicalDataProvider<TaskMaster, Void> {
...
@Override
public int getChildCount(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
if (query.getParent() != null) {
int count = service.getChildCount(query.getParent());
logger.info("child count: {}", count);
}
return service.getChildCount(query.getParent());
}
@Override
public boolean hasChildren(TaskMaster item) {
logger.info("item: {}", item);
return service.hasChildren(item);
}
@Override
protected Stream<TaskMaster> fetchChildrenFromBackEnd(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
return service.getChildren(query.getParent()).stream();
}
}
任务主管服务:
@Service
@Transactional
public class TaskMasterService {
...
public List<TaskMaster> getTopLevelTasks() {
List<TaskMaster> result = new ArrayList<>();
List<String> topLevelIDs = taskRelationService.getTopLevelParentTaskIDs();
topLevelIDs.forEach(id -> {
TaskMaster task = taskMasterRepo.findByInternalTaskID(id);
if (task != null) {
result.add(task);
}
});
return result;
}
public int getChildCount(TaskMaster parent) {
logger.info("parent: {}", parent);
return parent != null
? taskRelationService.getChildRelationsForParent(parent.getInternalTaskID()).size()
: 0;
}
public boolean hasChildren(TaskMaster parent) {
logger.info("parent: {}", parent);
return parent != null
? !taskRelationService.getChildRelationsForParent(parent.getInternalTaskID()).isEmpty()
: false;
}
public List<TaskMaster> getChildren(TaskMaster parent) {
logger.info("parent: {}", parent);
List<TaskMaster> result = new ArrayList<>();
if (parent != null) {
List<TaskRelationship> childRelations = taskRelationService
.getChildRelationsForParent(parent.getInternalTaskID());
childRelations.forEach(relation -> {
result.add(taskMasterRepo.findByInternalTaskID(relation.getChildTaskID()));
});
}
return result;
}
}
任务树视图:
@Route("tree")
@CssImport("./styles/shared-styles.css")
public class TaskTreeView extends VerticalLayout {
...
private TreeGrid<TaskMaster> taskGrid;
private TaskMasterDataProvider provider;
private TaskMasterService taskService;
public TaskTreeView(TaskMasterService taskService) {
this.taskService = taskService;
setSizeFull();
addClassName("task-tree-grid");
configureView();
}
private void configureView() {
taskGrid = new TreeGrid<>();
taskGrid.addHierarchyColumn(TaskMaster::getName).setHeader("Name");
taskGrid.addColumn(TaskMaster::getType).setHeader("Type");
taskGrid.getColumns().forEach(col -> {
col.setAutoWidth(true);
col.setResizable(true);
});
provider = new TaskMasterDataProvider(taskService);
taskGrid.setDataProvider(provider);
taskGrid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() != null) {
provider.refreshItem(event.getValue(), true);
}
});
add(taskGrid);
taskGrid.setItems(taskService.getTopLevelTasks());
}
}
这不是全部,但我认为这是最重要的。如果需要我可以添加更多。
如果有人知道我的理论是否有任何价值,或者我做的事情是否完全错误,请告诉我。
您为 treeGrid 设置了两次数据提供者
来过一次
taskGrid.setDataProvider(provider);
这里还有一个
taskGrid.setItems(taskService.getTopLevelTasks());
我认为您应该删除 setItems 指令并且 fetchChildrenFromBackEnd 的实现应该类似于
@Override
protected Stream<TaskMaster> fetchChildrenFromBackEnd(HierarchicalQuery<TaskMaster,
Void> query) {
logger.info("parent: {}", query.getParent());
if (null == query.getParent()) {
return taskService.getTopLevelTasks().stream();
}
return service.getChildren(query.getParent()).stream();
}
感谢@tremendous7 给了我导致解决方案的想法。除了给出的想法之外,我还遗漏了数据提供程序 getChildCount() 方法中的一个关键逻辑:
@Override
public int getChildCount(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
int count = 0;
if (query.getParent() == null) {
count = service.getTopLevelTasks().size();
} else {
count = service.getChildCount(query.getParent());
}
logger.info("child count: {}", count);
return count;
}
我正在尝试使用 Vaadin TreeGrid
.
需要注意的一件非常重要的事情是树节点类型不包含对父节点或任何子节点的引用。相反,一个单独的类型包含 parent/child 关系,引用树节点类型的项目的唯一 ID。
这两种类型分别存储在各自的数据库表中。数据本身是从 MS Excel 文件中提取的(不要问为什么)并插入到数据库中,应用程序利用该数据库访问数据。
为了更直观地呈现:
TaskMaster(树节点类型):
@Entity
public class TaskMaster extends AbstractEntity {
private String internalTaskID;
private String name;
private TaskType type;
// other fields
...
}
TaskRelationship(parent/child 关系):
@Entity
public class TaskRelationship extends AbstractEntity {
private String taskView;
private String parentTaskID;
private String childTaskID;
// other fields
...
}
我写了 @Repository
和 @Service
类 以方便根据需要检索信息。
我不知道如何让网格加载和显示代表任务树的节点层次结构。我查看了 Vaadin 示例,并创建了一个数据提供程序来尝试加载此数据,但无济于事。它仅加载根节点,不加载任何其他内容。
我想知道当节点对象包含对父子节点的引用时,树状网格是否只知道如何处理层次关系。 我的对象不这样做。 相反,我尝试在服务和数据提供程序中设置逻辑 类 以“获取”所需内容。显然那是行不通的。或者我错过了一些非常微妙的东西。
下面是代表我努力的一些代码。
任务主数据提供者:
public class TaskMasterDataProvider
extends AbstractBackEndHierarchicalDataProvider<TaskMaster, Void> {
...
@Override
public int getChildCount(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
if (query.getParent() != null) {
int count = service.getChildCount(query.getParent());
logger.info("child count: {}", count);
}
return service.getChildCount(query.getParent());
}
@Override
public boolean hasChildren(TaskMaster item) {
logger.info("item: {}", item);
return service.hasChildren(item);
}
@Override
protected Stream<TaskMaster> fetchChildrenFromBackEnd(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
return service.getChildren(query.getParent()).stream();
}
}
任务主管服务:
@Service
@Transactional
public class TaskMasterService {
...
public List<TaskMaster> getTopLevelTasks() {
List<TaskMaster> result = new ArrayList<>();
List<String> topLevelIDs = taskRelationService.getTopLevelParentTaskIDs();
topLevelIDs.forEach(id -> {
TaskMaster task = taskMasterRepo.findByInternalTaskID(id);
if (task != null) {
result.add(task);
}
});
return result;
}
public int getChildCount(TaskMaster parent) {
logger.info("parent: {}", parent);
return parent != null
? taskRelationService.getChildRelationsForParent(parent.getInternalTaskID()).size()
: 0;
}
public boolean hasChildren(TaskMaster parent) {
logger.info("parent: {}", parent);
return parent != null
? !taskRelationService.getChildRelationsForParent(parent.getInternalTaskID()).isEmpty()
: false;
}
public List<TaskMaster> getChildren(TaskMaster parent) {
logger.info("parent: {}", parent);
List<TaskMaster> result = new ArrayList<>();
if (parent != null) {
List<TaskRelationship> childRelations = taskRelationService
.getChildRelationsForParent(parent.getInternalTaskID());
childRelations.forEach(relation -> {
result.add(taskMasterRepo.findByInternalTaskID(relation.getChildTaskID()));
});
}
return result;
}
}
任务树视图:
@Route("tree")
@CssImport("./styles/shared-styles.css")
public class TaskTreeView extends VerticalLayout {
...
private TreeGrid<TaskMaster> taskGrid;
private TaskMasterDataProvider provider;
private TaskMasterService taskService;
public TaskTreeView(TaskMasterService taskService) {
this.taskService = taskService;
setSizeFull();
addClassName("task-tree-grid");
configureView();
}
private void configureView() {
taskGrid = new TreeGrid<>();
taskGrid.addHierarchyColumn(TaskMaster::getName).setHeader("Name");
taskGrid.addColumn(TaskMaster::getType).setHeader("Type");
taskGrid.getColumns().forEach(col -> {
col.setAutoWidth(true);
col.setResizable(true);
});
provider = new TaskMasterDataProvider(taskService);
taskGrid.setDataProvider(provider);
taskGrid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() != null) {
provider.refreshItem(event.getValue(), true);
}
});
add(taskGrid);
taskGrid.setItems(taskService.getTopLevelTasks());
}
}
这不是全部,但我认为这是最重要的。如果需要我可以添加更多。
如果有人知道我的理论是否有任何价值,或者我做的事情是否完全错误,请告诉我。
您为 treeGrid 设置了两次数据提供者 来过一次
taskGrid.setDataProvider(provider);
这里还有一个
taskGrid.setItems(taskService.getTopLevelTasks());
我认为您应该删除 setItems 指令并且 fetchChildrenFromBackEnd 的实现应该类似于
@Override
protected Stream<TaskMaster> fetchChildrenFromBackEnd(HierarchicalQuery<TaskMaster,
Void> query) {
logger.info("parent: {}", query.getParent());
if (null == query.getParent()) {
return taskService.getTopLevelTasks().stream();
}
return service.getChildren(query.getParent()).stream();
}
感谢@tremendous7 给了我导致解决方案的想法。除了给出的想法之外,我还遗漏了数据提供程序 getChildCount() 方法中的一个关键逻辑:
@Override
public int getChildCount(HierarchicalQuery<TaskMaster, Void> query) {
logger.info("parent: {}", query.getParent());
int count = 0;
if (query.getParent() == null) {
count = service.getTopLevelTasks().size();
} else {
count = service.getChildCount(query.getParent());
}
logger.info("child count: {}", count);
return count;
}