bknd-delete-entity

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Delete Entity

删除实体

Safely remove an entity (table) from Bknd, handling dependencies and avoiding data loss.
安全地从Bknd中删除实体(数据表),处理依赖关系并避免数据丢失。

Prerequisites

前提条件

  • Existing Bknd app with entities (see
    bknd-create-entity
    )
  • For code mode: Access to
    bknd.config.ts
  • Critical: Backup database before deletion
  • 已创建包含实体的Bknd应用(可参考
    bknd-create-entity
  • 代码模式下:拥有
    bknd.config.ts
    的访问权限
  • 关键操作: 删除前请备份数据库

Warning: Destructive Operation

警告:破坏性操作

Deleting an entity:
  • Permanently removes the table and ALL its data
  • Removes all relationships involving this entity
  • May break application code referencing this entity
  • Cannot be undone without database restore
删除实体将:
  • 永久移除数据表及其所有数据
  • 删除涉及该实体的所有关联关系
  • 可能导致引用该实体的应用代码失效
  • 若无数据库备份则无法撤销操作

When to Use UI vs Code

UI模式与代码模式的适用场景

Use UI Mode When

适用UI模式的场景

  • Quick prototype cleanup
  • Development/testing environments
  • Exploring what dependencies exist
  • 快速清理原型
  • 开发/测试环境
  • 探索实体间的依赖关系

Use Code Mode When

适用代码模式的场景

  • Production changes
  • Version control needed
  • Team collaboration
  • Reproducible deployments

  • 生产环境变更
  • 需要版本控制
  • 团队协作
  • 可重复部署的变更

Pre-Deletion Checklist

删除前检查清单

Before deleting an entity, verify:
删除实体前,请确认以下内容:

1. Check for Relationships

1. 检查关联关系

Entities may be referenced by other entities via:
  • Foreign keys (many-to-one)
  • Junction tables (many-to-many)
  • Self-references
实体可能通过以下方式被其他实体引用:
  • 外键(多对一关系)
  • 关联表(多对多关系)
  • 自引用

2. Check for Data

2. 检查数据量

typescript
const api = app.getApi();
const count = await api.data.count("entity_to_delete");
console.log(`Records to delete: ${count.data.count}`);
typescript
const api = app.getApi();
const count = await api.data.count("entity_to_delete");
console.log(`Records to delete: ${count.data.count}`);

3. Check for Code References

3. 检查代码引用

Search codebase for:
  • Entity name in queries:
    "entity_name"
  • Type references:
    DB["entity_name"]
  • API calls:
    api.data.*("entity_name")
在代码库中搜索:
  • 查询语句中的实体名称:
    "entity_name"
  • 类型引用:
    DB["entity_name"]
  • API调用:
    api.data.*("entity_name")

4. Backup Data (If Needed)

4. 备份数据(如需)

typescript
// Export data before deletion
const api = app.getApi();
const allRecords = await api.data.readMany("entity_to_delete", {
  limit: 100000,
});

// Save to file
import { writeFileSync } from "fs";
writeFileSync(
  "backup-entity_to_delete.json",
  JSON.stringify(allRecords.data, null, 2)
);

typescript
// 删除前导出数据
const api = app.getApi();
const allRecords = await api.data.readMany("entity_to_delete", {
  limit: 100000,
});

// 保存到文件
import { writeFileSync } from "fs";
writeFileSync(
  "backup-entity_to_delete.json",
  JSON.stringify(allRecords.data, null, 2)
);

Code Approach

代码操作步骤

Step 1: Identify Dependencies

步骤1:识别依赖关系

Check your schema for relationships:
typescript
// Look for relationships involving this entity
const schema = em(
  {
    users: entity("users", { email: text().required() }),
    posts: entity("posts", { title: text().required() }),
    comments: entity("comments", { body: text() }),
  },
  ({ relation }, { users, posts, comments }) => {
    // posts depends on users (foreign key)
    relation(posts).manyToOne(users);
    // comments depends on posts (foreign key)
    relation(comments).manyToOne(posts);
  }
);
Dependency order matters: Delete children before parents.
检查schema中的关联关系:
typescript
// 查找涉及该实体的关联关系
const schema = em(
  {
    users: entity("users", { email: text().required() }),
    posts: entity("posts", { title: text().required() }),
    comments: entity("comments", { body: text() }),
  },
  ({ relation }, { users, posts, comments }) => {
    // posts依赖于users(外键)
    relation(posts).manyToOne(users);
    // comments依赖于posts(外键)
    relation(comments).manyToOne(posts);
  }
);
依赖顺序至关重要: 先删除子实体,再删除父实体。

Step 2: Remove Relationships First

步骤2:先移除关联关系

If entity is a target of relationships, update schema to remove them:
typescript
// BEFORE: posts references users
const schema = em(
  {
    users: entity("users", { email: text().required() }),
    posts: entity("posts", { title: text().required() }),
  },
  ({ relation }, { users, posts }) => {
    relation(posts).manyToOne(users);
  }
);

// AFTER: Remove relationship before deleting users
const schema = em({
  users: entity("users", { email: text().required() }),
  posts: entity("posts", { title: text().required() }),
});
如果该实体是其他实体关联的目标,先更新schema移除关联关系:
typescript
// 之前:posts引用users
const schema = em(
  {
    users: entity("users", { email: text().required() }),
    posts: entity("posts", { title: text().required() }),
  },
  ({ relation }, { users, posts }) => {
    relation(posts).manyToOne(users);
  }
);

// 之后:删除users前先移除关联关系
const schema = em({
  users: entity("users", { email: text().required() }),
  posts: entity("posts", { title: text().required() }),
});

Step 3: Remove Entity from Schema

步骤3:从Schema中移除实体

Simply remove the entity definition from your
bknd.config.ts
:
typescript
// BEFORE
const schema = em({
  users: entity("users", { email: text().required() }),
  posts: entity("posts", { title: text().required() }),
  deprecated_entity: entity("deprecated_entity", { data: text() }),
});

// AFTER - entity removed
const schema = em({
  users: entity("users", { email: text().required() }),
  posts: entity("posts", { title: text().required() }),
});
直接从
bknd.config.ts
中删除实体定义:
typescript
// 之前
const schema = em({
  users: entity("users", { email: text().required() }),
  posts: entity("posts", { title: text().required() }),
  deprecated_entity: entity("deprecated_entity", { data: text() }),
});

// 之后 - 已移除实体
const schema = em({
  users: entity("users", { email: text().required() }),
  posts: entity("posts", { title: text().required() }),
});

Step 4: Preview Changes

步骤4:预览变更

bash
undefined
bash
undefined

See what will be dropped (dry run)

查看将被删除的内容(试运行)

npx bknd sync

Output shows:
Tables to drop: deprecated_entity Columns affected: (none on other tables)
undefined
npx bknd sync

输出示例:
Tables to drop: deprecated_entity Columns affected: (none on other tables)
undefined

Step 5: Apply Deletion

步骤5:执行删除

bash
undefined
bash
undefined

Apply with drop flag (destructive)

使用--drop标志应用变更(破坏性操作)

npx bknd sync --drop

Or with force (enables all destructive operations):
```bash
npx bknd sync --force
npx bknd sync --drop

或使用force标志(启用所有破坏性操作):
```bash
npx bknd sync --force

Step 6: Clean Up Code

步骤6:清理代码

Remove all references:
  • Delete type definitions
  • Remove API calls
  • Update imports

移除所有引用:
  • 删除类型定义
  • 移除API调用
  • 更新导入语句

UI Approach

UI操作步骤

Step 1: Open Admin Panel

步骤1:打开管理面板

Navigate to
http://localhost:1337
(or your configured URL).
访问
http://localhost:1337
(或您配置的URL)。

Step 2: Go to Data Section

步骤2:进入数据板块

Click Data in the sidebar.
点击侧边栏的Data选项。

Step 3: Select Entity

步骤3:选择实体

Click on the entity you want to delete.
点击您要删除的实体。

Step 4: Check Dependencies

步骤4:检查依赖关系

Look for:
  • Relations tab/section showing connected entities
  • Warning messages about dependencies
查看:
  • 显示关联实体的Relations标签/板块
  • 关于依赖关系的警告信息

Step 5: Export Data (Optional)

步骤5:导出数据(可选)

If you need the data:
  1. Go to entity's data view
  2. Export or manually copy records
  3. Save backup externally
如果需要保留数据:
  1. 进入实体的数据视图
  2. 导出或手动复制记录
  3. 外部保存备份

Step 6: Delete Entity

步骤6:删除实体

  1. Open entity settings (gear icon or settings tab)
  2. Look for Delete Entity or Remove button
  3. Confirm deletion
  4. Entity and all data removed
  1. 打开实体设置(齿轮图标或设置标签)
  2. 找到Delete EntityRemove按钮
  3. 确认删除操作
  4. 实体及其所有数据将被移除

Step 7: Sync Database

步骤7:同步数据库

After deletion, ensure database is synced:
  • Click Sync Database if prompted
  • Or run
    npx bknd sync --drop
    from CLI

删除后,确保数据库已同步:
  • 如有提示,点击Sync Database
  • 或从CLI执行
    npx bknd sync --drop

Handling Dependencies

依赖关系处理

Scenario: Entity Has Child Records

场景:实体包含子记录

Problem: Deleting
users
when
posts
has
users_id
foreign key.
Solution 1: Delete Children First
typescript
// 1. Delete all posts referencing users
const api = app.getApi();
await api.data.deleteMany("posts", {});

// 2. Then delete users
// (via schema removal + sync)
Solution 2: Remove Relationship First
typescript
// 1. Remove relationship from schema
// 2. Sync to remove foreign key
// 3. Remove entity from schema
// 4. Sync again with --drop
问题:
posts
表包含
users_id
外键时,删除
users
实体。
解决方案1:先删除子实体
typescript
// 1. 删除所有引用users的posts记录
const api = app.getApi();
await api.data.deleteMany("posts", {});

// 2. 再删除users实体
// (通过移除schema定义 + 同步操作)
解决方案2:先移除关联关系
typescript
// 1. 从schema中移除关联关系
// 2. 同步以移除外键
// 3. 从schema中移除实体
// 4. 再次执行sync --drop

Scenario: Entity is Junction Table Target

场景:实体是关联表的目标

Problem:
tags
is used in
posts_tags
junction table.
Solution:
typescript
// 1. Remove many-to-many relationship
const schema = em(
  {
    posts: entity("posts", { title: text() }),
    tags: entity("tags", { name: text() }),
  }
  // Remove: ({ relation }, { posts, tags }) => { relation(posts).manyToMany(tags); }
);

// 2. Sync to drop junction table
// npx bknd sync --drop

// 3. Remove tags entity
const schema = em({
  posts: entity("posts", { title: text() }),
});

// 4. Sync again to drop tags table
// npx bknd sync --drop
问题:
tags
实体被用于
posts_tags
关联表中。
解决方案:
typescript
// 1. 移除多对多关联关系
const schema = em(
  {
    posts: entity("posts", { title: text() }),
    tags: entity("tags", { name: text() }),
  }
  // 移除:({ relation }, { posts, tags }) => { relation(posts).manyToMany(tags); }
);

// 2. 同步以删除关联表
// npx bknd sync --drop

// 3. 移除tags实体
const schema = em({
  posts: entity("posts", { title: text() }),
});

// 4. 再次同步以删除tags表
// npx bknd sync --drop

Scenario: Self-Referencing Entity

场景:自引用实体

Problem:
categories
references itself (parent/children).
Solution:
typescript
// 1. Remove self-reference relation
const schema = em({
  categories: entity("categories", { name: text() }),
  // Remove self-referencing relation definition
});

// 2. Sync to remove foreign key
// npx bknd sync --drop

// 3. Remove entity
// (then sync again)

问题:
categories
实体自引用(父/子分类)。
解决方案:
typescript
// 1. 移除自引用关联关系
const schema = em({
  categories: entity("categories", { name: text() }),
  // 移除自引用关联关系定义
});

// 2. 同步以移除外键
// npx bknd sync --drop

// 3. 移除实体
// (然后再次同步)

Deleting Multiple Entities

删除多个实体

Order matters. Delete in dependency order (children first):
typescript
// Dependency tree:
// users <- posts <- comments
//       <- likes

// Delete order:
// 1. comments (depends on posts)
// 2. likes (depends on posts)
// 3. posts (depends on users)
// 4. users (no dependencies)
顺序至关重要。按照依赖顺序删除(先子后父):
typescript
// 依赖树:
// users <- posts <- comments
//       <- likes

// 删除顺序:
// 1. comments(依赖于posts)
// 2. likes(依赖于posts)
// 3. posts(依赖于users)
// 4. users(无依赖)

Batch Deletion Script

批量删除脚本

typescript
// scripts/cleanup-entities.ts
import { App } from "bknd";

async function cleanup() {
  const app = new App({
    connection: { url: process.env.DB_URL! },
  });
  await app.build();
  const api = app.getApi();

  // Delete in order
  const entitiesToDelete = ["comments", "likes", "posts"];

  for (const entity of entitiesToDelete) {
    const count = await api.data.count(entity);
    console.log(`Deleting ${count.data.count} records from ${entity}...`);
    await api.data.deleteMany(entity, {});
    console.log(`Deleted all records from ${entity}`);
  }

  console.log("Data cleanup complete. Now remove from schema and sync.");
}

cleanup().catch(console.error);

typescript
// scripts/cleanup-entities.ts
import { App } from "bknd";

async function cleanup() {
  const app = new App({
    connection: { url: process.env.DB_URL! },
  });
  await app.build();
  const api = app.getApi();

  // 按顺序删除
  const entitiesToDelete = ["comments", "likes", "posts"];

  for (const entity of entitiesToDelete) {
    const count = await api.data.count(entity);
    console.log(`Deleting ${count.data.count} records from ${entity}...`);
    await api.data.deleteMany(entity, {});
    console.log(`Deleted all records from ${entity}`);
  }

  console.log("数据清理完成。现在请从schema中移除实体并同步。");
}

cleanup().catch(console.error);

Common Pitfalls

常见陷阱

Foreign Key Constraint Error

外键约束错误

Error:
Cannot drop table: foreign key constraint
Cause: Another entity references this one.
Fix: Remove relationship first, sync, then remove entity.
错误信息:
Cannot drop table: foreign key constraint
原因: 其他实体引用了该实体。
解决方法: 先移除关联关系,同步后再删除实体。

Junction Table Not Dropped

关联表未被删除

Problem: After removing many-to-many relation, junction table remains.
Fix: Run
npx bknd sync --drop
to include destructive operations.
问题: 移除多对多关联关系后,关联表仍存在。
解决方法: 执行
npx bknd sync --drop
以包含破坏性操作。

Entity Still Appears in UI

实体仍在UI中显示

Problem: Deleted from code but still shows in admin panel.
Fix:
  • Ensure you ran
    npx bknd sync --drop
  • Restart the Bknd server
  • Clear browser cache
问题: 已通过代码删除实体,但管理面板中仍可见。
解决方法:
  • 确保已执行
    npx bknd sync --drop
  • 重启Bknd服务器
  • 清除浏览器缓存

Application Crashes After Deletion

删除后应用崩溃

Problem: Code still references deleted entity.
Fix:
  • Search codebase:
    grep -r "entity_name" src/
  • Remove all API calls, types, imports
  • Fix TypeScript errors
问题: 代码仍引用已删除的实体。
解决方法:
  • 在代码库中搜索:
    grep -r "entity_name" src/
  • 移除所有API调用、类型定义和导入语句
  • 修复TypeScript错误

Accidentally Deleted Wrong Entity

误删错误实体

Problem: Deleted production data.
Fix:
  • If you have backup: Restore from backup
  • If no backup: Data is permanently lost
  • Prevention: Always backup before deletion

问题: 删除了生产环境中的数据。
解决方法:
  • 若有备份:从备份恢复
  • 若无备份:数据将永久丢失
  • 预防措施:删除前务必备份

Verification

验证操作

After Deletion

删除后检查

bash
undefined
bash
undefined

1. Check schema export (entity should be absent)

1. 检查schema导出(实体应不存在)

npx bknd schema --pretty | grep entity_name
npx bknd schema --pretty | grep entity_name

2. Verify sync status

2. 验证同步状态

npx bknd sync
npx bknd sync

Should show no pending changes

应显示无待处理变更

undefined
undefined

Via Code

通过代码验证

typescript
const api = app.getApi();

// This should fail/return error for deleted entity
try {
  await api.data.readMany("deleted_entity", { limit: 1 });
  console.log("ERROR: Entity still exists!");
} catch (e) {
  console.log("Confirmed: Entity deleted successfully");
}
typescript
const api = app.getApi();

// 已删除的实体应返回错误
try {
  await api.data.readMany("deleted_entity", { limit: 1 });
  console.log("错误:实体仍存在!");
} catch (e) {
  console.log("确认:实体已成功删除");
}

Via REST API

通过REST API验证

bash
undefined
bash
undefined

Should return 404 or error

应返回404或错误

DOs and DON'Ts

注意事项

DO:
  • Backup data before deletion
  • Check for dependencies first
  • Delete children before parents
  • Preview with
    npx bknd sync
    before
    --drop
  • Remove code references after deletion
  • Test in development before production
DON'T:
  • Delete entities with active foreign keys
  • Use
    --drop
    without previewing changes
  • Delete in production without backup
  • Assume UI deletion handles all cleanup
  • Forget to remove TypeScript types/code references

请遵循:
  • 删除前备份数据
  • 先检查依赖关系
  • 先删除子实体再删除父实体
  • 执行
    --drop
    前先用
    npx bknd sync
    预览变更
  • 删除后移除代码中的引用
  • 先在开发环境测试再部署到生产环境
请勿:
  • 删除存在活跃外键引用的实体
  • 未预览变更就使用
    --drop
  • 无备份时在生产环境删除实体
  • 认为UI删除能处理所有清理工作
  • 忘记移除TypeScript类型和代码引用

Related Skills

相关技能

  • bknd-create-entity - Create new entities
  • bknd-modify-schema - Modify existing schema
  • bknd-define-relationship - Understand relationship dependencies
  • bknd-crud-delete - Delete individual records (not tables)
  • bknd-seed-data - Restore data from backup
  • bknd-create-entity - 创建新实体
  • bknd-modify-schema - 修改现有schema
  • bknd-define-relationship - 理解关联关系依赖
  • bknd-crud-delete - 删除单个记录(非数据表)
  • bknd-seed-data - 从备份恢复数据