Prisma 自引用与菜单实战

一、什么是 Primsa 自引用?

"自引用" 通常指的是一个数据结构或对象引用自身的情况。

在数据库模型中,自引用可能指的是在一个表中的某一列引用了同一表中的其他行的数据,通常用来表示层次结构。

二、自引用解决了哪些问题?

  • 菜单(多级菜单、动态菜单、权限管理)
  • 评论与回复
  • 组织结构
  • 目录结构
  • 分类系统
  • 社交关系
  • 有向图

三、菜单示例

本示例一 sqlite 为例, 包含一个菜单项目的 Schema 文件

schema 复制代码
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

model MenuItem {
  id        Int      @id @default(autoincrement())
  label     String
  parent    MenuItem? @relation("ChildToParent", fields: [parentId], references: [id])
  parentId  Int?
  children  MenuItem[] @relation("ChildToParent")
}

四、解析

此 Schema 只有一个 label 是实际字段,假设它保存就是 路由路径

  • children 字段关联 MenuItem 类型也就是它自己
  • parent 字段通过 parentId 与自己关联

由此形成了一个简单的 自引用关系,其中包含了 父与子 是一对多的关系,而 子与父 是多对一的关系。

五、制作模型工具

ts 复制代码
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

prisma.$connect().then((err) => {
  console.log(err);
});

export { prisma };

六、创建菜单根路由

ts 复制代码
const createMenuItemRoot = async () => {
  const menuItem = await prisma.menuItem.create({
    data: {
      label: '/',
    },
  });
  console.log('created menu items ', menuItem);
};

createMenuItemRoot()

在数据库中插入一条路由的顶层数据,也就是根路由。

七、创建子路由

ts 复制代码
const createMenuItem = async (label, parentId) => {
  const menuItem = await prisma.menuItem.create({
    data: {
      label,
      parentId,
    },
  });
  console.log('created menu items ', menuItem);
};

八、创建子路由示例

创建三个一级菜单:

ts 复制代码
createMenuItem('/dashboard', 1); // id 2
createMenuItem('/analysis', 1);
createMenuItem('/monitor', 1);

给 dashboard 路由创建子菜单

ts 复制代码
createMenuItem('/analysis/p1', 2);
createMenuItem('/analysis/p2', 2);

得到的表的结构:

九、获取列表

ts 复制代码
const findAll = async () => {
  const menus = await prisma.menuItem.findMany();
  console.log(menus);
};

十、深层次查找

使用 prisma 进行深层次查找(也就是查找 children):

ts 复制代码
const findChildren = async () => {
  const menus = await prisma.menuItem.findMany({
    where: {
      id: 1,
    },
    include: {
      children: {
        where: {
          parentId: 1,
        },
        include: {
          children: {
            where: {
              parentId: 2,
            },
          },
        },
      },
    },
  });
  console.log(menus[0].children);
};

十一、根据 id 查询所有的子菜单

使用 递归 的方式,查询菜单的所有菜单。

ts 复制代码
async function getMenus(menuId) {
  const node = await prisma.menuItem.findUnique({
    where: { id: menuId },
    include: {
      children: {
        where: {
          parentId: menuId,
        },
      },
    },
  });

  if (!node) {
    return {};
  }

  if (node.children.length > 0) {
    for (const child of node.children) {
      const childNodes = await getMenus(child.id);
      child.children = childNodes;
    }
  }

  return node;
}

十二、获取子引用表中的菜单

ts 复制代码
getMenus(1) // 顶级

当能够方便的查询到树状结构的数据的时候,我们就能方便的展示在管理系统的权限管理中。

十三、小结

本文主要讲解Prsima 的自引用的模型以及关于菜单使用方式。自引用解决了类似树状数据结构问题,以菜单为例,当我们需要查询一个角色的对应的菜单的时候,此时自引用数据结构就会变得非常有用。

相关推荐
xuejianxinokok10 分钟前
新版本 python 3.14 性能到底如何?
后端·python
Ray6612 分钟前
代理模式
后端
考虑考虑13 分钟前
Jpa中的枚举类型
spring boot·后端·spring
布列瑟农的星空15 分钟前
重学React——memo能防止Context的额外渲染吗
前端
FuckPatience16 分钟前
Vue 与.Net Core WebApi交互时路由初探
前端·javascript·vue.js
peter52716 分钟前
LangChain4j入门使用
后端
小小前端_我自坚强21 分钟前
前端踩坑指南 - 避免这些常见陷阱
前端·程序员·代码规范
ArabySide22 分钟前
【ASP.NET Core】分布式场景下ASP.NET Core中JWT应用教程
分布式·后端·asp.net core
lichenyang45323 分钟前
从零实现JSON与图片文件上传功能
前端
WebGirl25 分钟前
动态生成多层表头表格算法
前端·javascript