Skip to Content
文档Entityengine核心概念实体模型

实体模型

定义应用的数据结构和业务规则。实体模型告诉 Entity Engine 您的数据长什么样子,有哪些字段,以及如何验证和处理这些数据。

创建第一个模型

最简单的方式是定义一个包含基本字段的用户模型。每个模型都需要一个名称、标题,以及字段列表:

import { getEntityEngine } from './lib/entity-engine'; const engine = await getEntityEngine(); // 注册用户模型 await engine.metaRegistry.updateOrRegister({ name: 'User', // 模型名称,用于代码中引用 title: '用户', // 显示名称,用于UI界面 fields: [ { name: 'name', // 字段名称 title: '姓名', // 字段显示名称 type: 'string', // 字段类型 isRequired: true // 是否必填 }, { name: 'email', title: '邮箱', type: 'string', isRequired: true }, { name: 'age', title: '年龄', type: 'number', isRequired: false // 可选字段 } ] });

注册完成后,您就可以使用这个模型进行数据操作了。Entity Engine 会根据模型定义自动处理数据验证、存储和查询。

字段类型详解

基础字段类型

Entity Engine 支持多种字段类型,每种类型都有不同的验证规则和显示方式。选择正确的字段类型可以确保数据的准确性和用户体验。

const productModel = { name: 'Product', title: '产品', fields: [ // 文本字段 - 存储短文本内容 { name: 'name', title: '产品名称', type: 'string', isRequired: true }, // 数字字段 - 存储数值 { name: 'price', title: '价格', type: 'number', isRequired: true }, // 布尔字段 - 存储真/假值 { name: 'isActive', title: '是否启用', type: 'boolean', defaultValue: true // 默认值 }, // 日期字段 - 存储日期和时间 { name: 'createdAt', title: '创建时间', type: 'datetime', defaultValue: 'now' // 使用当前时间作为默认值 }, // 长文本字段 - 存储多行文本 { name: 'description', title: '产品描述', type: 'text' } ] }; await engine.metaRegistry.updateOrRegister(productModel);

关联字段类型

当您需要在不同的数据之间建立关系时,可以使用关联字段。这让您可以轻松地查询相关数据。

// 先定义分类模型 await engine.metaRegistry.updateOrRegister({ name: 'Category', title: '分类', fields: [ { name: 'name', title: '分类名称', type: 'string', isRequired: true } ] }); // 然后在产品模型中引用分类 await engine.metaRegistry.updateOrRegister({ name: 'Product', title: '产品', fields: [ { name: 'name', title: '产品名称', type: 'string', isRequired: true }, // 多对一关联 - 每个产品属于一个分类 { name: 'category', title: '所属分类', type: 'many_to_one', refModel: 'Category', // 引用的模型名称 isRequired: true } ] });

这样设置后,您可以在查询产品时自动包含分类信息:

// 查询产品并包含分类信息 const products = await engine.datasource.listObjects({ modelName: 'Product', include: { category: true // 自动加载关联的分类数据 } }); // 结果会包含完整的分类信息 products.items.forEach(product => { console.log(`${product.name} - 分类: ${product.category.name}`); });

一对多关联

当一个记录需要关联多个相关记录时,使用一对多关联:

// 文章模型 await engine.metaRegistry.updateOrRegister({ name: 'Post', title: '文章', fields: [ { name: 'title', title: '标题', type: 'string', isRequired: true }, { name: 'content', title: '内容', type: 'text' } ] }); // 评论模型 - 多个评论属于一篇文章 await engine.metaRegistry.updateOrRegister({ name: 'Comment', title: '评论', fields: [ { name: 'content', title: '评论内容', type: 'text', isRequired: true }, { name: 'post', title: '所属文章', type: 'many_to_one', refModel: 'Post', isRequired: true } ] });

查询时可以包含所有相关的评论:

// 查询文章并包含所有评论 const posts = await engine.datasource.listObjects({ modelName: 'Post', include: { comments: true // 自动加载所有相关评论 } });

字段验证

设置字段约束

您可以为字段设置各种约束条件,确保数据的完整性和正确性:

await engine.metaRegistry.updateOrRegister({ name: 'User', title: '用户', fields: [ { name: 'username', title: '用户名', type: 'string', isRequired: true, unique: true, // 确保用户名唯一 minLength: 3, // 最小长度 maxLength: 20 // 最大长度 }, { name: 'email', title: '邮箱', type: 'string', isRequired: true, unique: true, pattern: '^[^@]+@[^@]+\\.[^@]+$' // 邮箱格式验证 }, { name: 'age', title: '年龄', type: 'number', min: 0, // 最小值 max: 150 // 最大值 } ] });

自定义验证规则

对于更复杂的验证需求,您可以定义自定义验证函数:

await engine.metaRegistry.updateOrRegister({ name: 'Order', title: '订单', fields: [ { name: 'orderNumber', title: '订单号', type: 'string', isRequired: true, validate: (value) => { // 订单号必须以 "ORD-" 开头,后跟8位数字 const pattern = /^ORD-\d{8}$/; if (!pattern.test(value)) { throw new Error('订单号格式无效,应为 ORD-12345678'); } return true; } }, { name: 'amount', title: '订单金额', type: 'number', isRequired: true, validate: (value) => { if (value <= 0) { throw new Error('订单金额必须大于0'); } if (value > 100000) { throw new Error('单次订单金额不能超过10万元'); } return true; } } ] });

当用户尝试创建或更新数据时,这些验证规则会自动执行:

try { await engine.datasource.createObject({ modelName: 'Order', values: { orderNumber: 'INVALID', // 这会触发验证错误 amount: 1000 } }); } catch (error) { console.error('验证失败:', error.message); // "订单号格式无效,应为 ORD-12345678" }

默认值和计算字段

设置默认值

您可以为字段设置默认值,这样在创建新记录时会自动填充:

await engine.metaRegistry.updateOrRegister({ name: 'Article', title: '文章', fields: [ { name: 'title', title: '标题', type: 'string', isRequired: true }, { name: 'status', title: '状态', type: 'string', defaultValue: 'draft' // 新文章默认为草稿状态 }, { name: 'createdAt', title: '创建时间', type: 'datetime', defaultValue: 'now' // 使用当前时间 }, { name: 'viewCount', title: '浏览次数', type: 'number', defaultValue: 0 // 初始浏览次数为0 } ] });

计算字段

计算字段的值根据其他字段动态计算得出:

await engine.metaRegistry.updateOrRegister({ name: 'OrderItem', title: '订单明细', fields: [ { name: 'quantity', title: '数量', type: 'number', isRequired: true }, { name: 'unitPrice', title: '单价', type: 'number', isRequired: true }, { name: 'totalPrice', title: '总价', type: 'number', computed: true, // 标记为计算字段 compute: (record) => { // 计算逻辑 return record.quantity * record.unitPrice; } } ] });

计算字段会在数据保存时自动更新:

const orderItem = await engine.datasource.createObject({ modelName: 'OrderItem', values: { quantity: 3, unitPrice: 299.99 // totalPrice 会自动计算为 899.97 } }); console.log(orderItem.totalPrice); // 899.97

模型权限设置

字段级权限

您可以为不同的字段设置不同的访问权限:

await engine.metaRegistry.updateOrRegister({ name: 'User', title: '用户', fields: [ { name: 'name', title: '姓名', type: 'string', isRequired: true // 所有用户都可以读写 }, { name: 'email', title: '邮箱', type: 'string', isRequired: true, readable: ['admin', 'self'], // 只有管理员和本人可以读取 writable: ['admin', 'self'] // 只有管理员和本人可以修改 }, { name: 'salary', title: '薪资', type: 'number', readable: ['admin'], // 只有管理员可以读取 writable: ['admin'] // 只有管理员可以修改 } ] });

记录级权限

您也可以设置整个记录的访问权限:

await engine.metaRegistry.updateOrRegister({ name: 'PrivateDocument', title: '私人文档', fields: [ { name: 'title', title: '标题', type: 'string', isRequired: true }, { name: 'content', title: '内容', type: 'text' }, { name: 'owner', title: '所有者', type: 'many_to_one', refModel: 'User', isRequired: true } ], // 记录级权限规则 permissions: { read: (record, user) => { // 只有所有者和管理员可以读取 return record.owner.id === user.userId || user.roles.includes('admin'); }, write: (record, user) => { // 只有所有者可以修改 return record.owner.id === user.userId; }, delete: (record, user) => { // 只有所有者和管理员可以删除 return record.owner.id === user.userId || user.roles.includes('admin'); } } });

模型继承

创建基础模型

当多个模型有相似的字段时,可以使用继承来减少重复定义:

// 基础内容模型 await engine.metaRegistry.updateOrRegister({ name: 'BaseContent', title: '基础内容', abstract: true, // 抽象模型,不能直接创建记录 fields: [ { name: 'title', title: '标题', type: 'string', isRequired: true }, { name: 'content', title: '内容', type: 'text' }, { name: 'createdAt', title: '创建时间', type: 'datetime', defaultValue: 'now' }, { name: 'author', title: '作者', type: 'many_to_one', refModel: 'User', isRequired: true } ] });

继承基础模型

其他模型可以继承基础模型的所有字段,然后添加自己特有的字段:

// 文章模型继承基础内容 await engine.metaRegistry.updateOrRegister({ name: 'Article', title: '文章', inherits: 'BaseContent', // 继承基础内容模型 fields: [ // 继承了 title, content, createdAt, author 字段 // 添加文章特有的字段 { name: 'category', title: '分类', type: 'many_to_one', refModel: 'Category' }, { name: 'publishedAt', title: '发布时间', type: 'datetime' } ] }); // 新闻模型也继承基础内容 await engine.metaRegistry.updateOrRegister({ name: 'News', title: '新闻', inherits: 'BaseContent', fields: [ // 添加新闻特有的字段 { name: 'urgency', title: '紧急程度', type: 'string', defaultValue: 'normal' }, { name: 'expiresAt', title: '过期时间', type: 'datetime' } ] });

实际应用示例

电商系统模型

这是一个完整的电商系统模型示例,展示了如何定义相互关联的多个模型:

// 用户模型 await engine.metaRegistry.updateOrRegister({ name: 'Customer', title: '客户', fields: [ { name: 'name', title: '姓名', type: 'string', isRequired: true }, { name: 'email', title: '邮箱', type: 'string', isRequired: true, unique: true }, { name: 'phone', title: '电话', type: 'string' }, { name: 'address', title: '地址', type: 'text' } ] }); // 商品分类 await engine.metaRegistry.updateOrRegister({ name: 'ProductCategory', title: '商品分类', fields: [ { name: 'name', title: '分类名称', type: 'string', isRequired: true }, { name: 'description', title: '描述', type: 'text' } ] }); // 商品模型 await engine.metaRegistry.updateOrRegister({ name: 'Product', title: '商品', fields: [ { name: 'name', title: '商品名称', type: 'string', isRequired: true }, { name: 'description', title: '商品描述', type: 'text' }, { name: 'price', title: '价格', type: 'number', isRequired: true, min: 0 }, { name: 'category', title: '分类', type: 'many_to_one', refModel: 'ProductCategory', isRequired: true }, { name: 'stock', title: '库存', type: 'number', defaultValue: 0, min: 0 }, { name: 'isActive', title: '是否上架', type: 'boolean', defaultValue: true } ] }); // 订单模型 await engine.metaRegistry.updateOrRegister({ name: 'Order', title: '订单', fields: [ { name: 'orderNumber', title: '订单号', type: 'string', isRequired: true, unique: true }, { name: 'customer', title: '客户', type: 'many_to_one', refModel: 'Customer', isRequired: true }, { name: 'status', title: '订单状态', type: 'string', defaultValue: 'pending', options: ['pending', 'paid', 'shipped', 'delivered', 'cancelled'] }, { name: 'totalAmount', title: '订单总额', type: 'number', isRequired: true, min: 0 }, { name: 'createdAt', title: '下单时间', type: 'datetime', defaultValue: 'now' } ] }); // 订单明细模型 await engine.metaRegistry.updateOrRegister({ name: 'OrderItem', title: '订单明细', fields: [ { name: 'order', title: '所属订单', type: 'many_to_one', refModel: 'Order', isRequired: true }, { name: 'product', title: '商品', type: 'many_to_one', refModel: 'Product', isRequired: true }, { name: 'quantity', title: '数量', type: 'number', isRequired: true, min: 1 }, { name: 'unitPrice', title: '单价', type: 'number', isRequired: true, min: 0 }, { name: 'totalPrice', title: '小计', type: 'number', computed: true, compute: (record) => record.quantity * record.unitPrice } ] });

使用模型进行业务操作

定义好模型后,您就可以进行各种业务操作了:

// 创建客户 const customer = await engine.datasource.createObject({ modelName: 'Customer', values: { name: '张三', email: 'zhangsan@example.com', phone: '13812345678' } }); // 创建商品分类 const category = await engine.datasource.createObject({ modelName: 'ProductCategory', values: { name: '电子产品', description: '各类电子设备' } }); // 创建商品 const product = await engine.datasource.createObject({ modelName: 'Product', values: { name: 'iPhone 15', description: '最新款苹果手机', price: 6999, category: category.id, stock: 100 } }); // 创建订单 const order = await engine.datasource.createObject({ modelName: 'Order', values: { orderNumber: 'ORD-20250101', customer: customer.id, status: 'pending', totalAmount: 6999 } }); // 创建订单明细 await engine.datasource.createObject({ modelName: 'OrderItem', values: { order: order.id, product: product.id, quantity: 1, unitPrice: 6999 // totalPrice 会自动计算 } });

最佳实践

模型命名规范

使用清晰、一致的命名规范可以让您的应用更易维护:

// ✅ 推荐:使用单数名词,首字母大写 const goodNames = [ 'User', // 不是 Users 'Product', // 不是 Products 'OrderItem', // 复合词使用驼峰命名 'BlogPost' // 不是 Blog_Post 或 blogpost ]; // ❌ 避免:模糊或过长的名称 const badNames = [ 'Data', // 太通用 'UserAccountInformation', // 太长 'u', // 太短 'user_info' // 使用下划线 ];

字段设计原则

设计字段时应该考虑数据的完整性和使用便利性:

// ✅ 推荐:明确的字段定义 { name: 'email', title: '邮箱地址', type: 'string', isRequired: true, unique: true, pattern: '^[^@]+@[^@]+\\.[^@]+$' // 明确的验证规则 } // ❌ 避免:模糊的字段定义 { name: 'data', // 名称不明确 title: 'Data', // 标题没有意义 type: 'text' // 没有验证规则 }

关联关系设计

合理设计关联关系可以让数据查询更高效:

// ✅ 推荐:明确的关联关系 { name: 'author', title: '作者', type: 'many_to_one', refModel: 'User', // 明确引用的模型 isRequired: true, // 明确是否必须 onDelete: 'restrict' // 明确删除策略 } // ❌ 避免:没有约束的关联 { name: 'user', type: 'many_to_one', refModel: 'User' // 缺少必要的约束和策略 }

现在您已经掌握了如何定义和使用实体模型。接下来可以学习如何创建用户界面视图来展示和编辑这些数据。

Last updated on