模型代表一组结构化数据,称为记录。模型通常对应于数据库中的表/集合,属性对应于列/字段,记录对应于行/文档。
按照惯例,模型是通过在 Sails 应用程序的 api/models/
文件夹中创建一个文件来定义的
// api/models/Product.js
module.exports = {
attributes: {
nameOnMenu: { type: 'string', required: true },
price: { type: 'string', required: true },
percentRealMeat: { type: 'number', defaultsTo: 20, columnType: 'FLOAT' },
numCalories: { type: 'number' },
},
};
有关设置模型定义时可用选项的完整演练,请参阅 模型设置、属性 和 关联。
一旦 Sails 应用程序运行,它的模型就可以从控制器操作、助手、测试以及您通常编写后端代码的任何其他地方访问。这允许您的代码的调用模型方法与您的数据库(甚至与多个数据库)进行通信。
模型上有许多内置方法可用,其中最重要的模型方法是 .find() 和 .create()。您可以在 参考 > Waterline (ORM) > 模型 中找到有关这些方法的详细用法文档。
Sails 中的每个模型都有一组公开的方法,允许您以规范化的方式与数据库进行交互。这是与应用程序数据交互的主要方式。
由于它们通常必须向数据库发送查询并等待响应,因此大多数模型方法都是异步的。也就是说,它们不会立即返回答案。与 JavaScript 中的其他异步逻辑(例如 setTimeout()
)一样,这意味着我们需要其他方法来确定它们何时完成执行,是否成功,以及如果没有,发生了什么类型的错误(或其他异常情况)。
在 Node.js、Sails 和 JavaScript 中,处理此问题的推荐方法是使用 async/await
。
有关使用查询的更多信息,请参阅 参考 > Waterline (ORM) > 查询。
Sails 还提供了一些其他“资源丰富的发布订阅”(或 RPS) 方法,专门用于使用动态房间执行简单的实时操作。有关这些方法的更多信息,请参阅 参考 > WebSockets > 资源丰富的发布订阅。
除了 Sails 提供的内置功能外,您还可以定义自己的自定义模型方法。自定义模型方法对于推断与特定模型相关的控制器代码最有用。它们允许代码从控制器中提取并插入可从任何地方调用的可重用函数(独立于 req
或 res
)。
此功能利用了模型忽略无法识别的设置这一事实,因此您需要小心不要无意中覆盖内置方法(例如,不要定义名为“create”的方法)。
如果您不确定,请改写一个 助手。
自定义模型方法可以是同步或异步函数,但大多数情况下,它们是异步的。按照惯例,异步模型方法应该是 async
函数,它们接受一个 options
字典作为参数。
例如
// in api/models/Monkey.js...
// Find monkeys with the same name as the specified person
findWithSameNameAsPerson: async function (opts) {
var person = await Person.findOne({ id: opts.id });
if (!person) {
throw require('flaverr')({
message: `Cannot find monkeys with the same name as the person w/ id=${opts.id} because that person does not exist.`,
code: 'E_UNKNOWN_PERSON'
});
}
return await Monkey.find({ name: person.name });
}
请注意,我们没有对该函数中的任何代码进行
try/catch
。这是因为我们打算将该责任留给调用我们函数的人。
然后你可以做
var monkeys = await Monkey.findWithSameNameAsPerson({id:37});
有关更多提示,请阅读关于 蒂莫西猴子 的事件。
从 Sails v1.0 开始,实例方法已从 Sails 和 Waterline 中删除。虽然像 .save()
和 .destroy()
这样的实例方法有时在应用程序代码中很方便,但在 Node.js 中,许多用户发现它们会导致意外的后果和设计缺陷。
例如,考虑一个管理婚礼记录的应用程序。在 Person 模型上编写一个实例方法来更新数据库中两个人的 spouse
属性似乎是一个好主意。这将允许您编写类似于以下的控制器代码
personA.marry(personB, function (err) {
if (err) { return res.serverError(err); }
return res.ok();
})
看起来很棒……直到要实现一个逻辑大致相同但只有“personA”的 ID(而不是整个记录)的稍微不同的操作时。在这种情况下,您别无选择,只能将实例方法重新编写为静态方法!
更好的策略是从一开始就编写一个自定义(静态)模型方法。这使您的函数更具可重用性/通用性,因为它无论您是否手边有实际的记录实例,都将可以访问。您可以将前面示例中的代码重构为类似于以下代码
Person.marry(personA.id, personB.id, function (err) {
if (err) { return res.serverError(err); }
return res.ok();
})
Sails v1.0 中的查询不再强制区分大小写,无论数据库如何处理查询。这极大地提高了查询性能,并更好地利用了索引。大多数数据库默认情况下是区分大小写的,但在极少数情况下,它们不是,并且您希望更改该行为,您必须修改数据库以实现这一点。
例如,MySQL 将使用默认情况下区分大小写的数据库排序规则。这与 sails-disk 不同,因此您可能会在开发到生产过程中遇到不同的结果。为了解决此问题,您可以将 MySQL 数据库中的表设置为区分大小写的排序规则,例如 utf8_bin
。