如果我更喜欢使用 raw 而不是其内置函数,那么使用 Knex 是否毫无意义?
Is it pointless to use Knex if I prefer using raw over its built-in functions?
我知道 Knex 有很多好处,这就是我考虑将它用于我的 Node 应用程序的原因。我以前用过它,我真的很喜欢用它来编写原始查询。 (注意:我仍处于 Knex 的学习阶段。)就个人而言,我认为它们使代码看起来比使用基本 SQL 稍微好一些。我的问题就是从这一点开始的,因为也许我的偏好在这里很愚蠢。
我也很想对 Knex 的内置功能发表意见。对于那些喜欢生的人来说,你喜欢他们什么?无论我选择哪种途径,我的目标都是在我的应用程序中保持一致性。
感谢您的意见!
这不是毫无意义的。这在一定程度上取决于您是否在团队环境中工作,还有谁可能必须维护它,以及他们对编写 SQL 查询的舒适程度。请注意,许多可以使用 Knex 完成的事情也可以使用直接数据库驱动程序完成,因此对于许多技术选择,它归结为 personal/team 偏好和易于维护。
即使假设您从不使用查询生成器,Knex 也提供:
- 根据目前的配置比较简单
NODE_ENV
- connection/pool 管理
- 简单的参数化
- 轻松交易
- 轻松迁移和播种
为什么不用.raw
?好吧,这是品尝者的选择,查询构建器并不适合所有人。但是,查询构建器的粉丝会告诉您:
- 当你不处理一堆原始数据时,在数据库后端之间迁移会更容易 SQL
- 许多人发现 Knex 语法更容易阅读,因为能够合理理解 JavaScript 承诺链的人数可能超过理解 SQL
的人数
- 它往往更紧凑
- 它比
.raw
提供了 name/syntax 级别的安全性(如果您使用的是 TypeScript,还提供编译时类型安全和编辑器支持)。
查询构建器也非常适合组合,因此:
const userPhoneNumbers = knex('users').select({ id, email });
// later...
const gmailUsers = userPhoneNumbers.where('email', 'ilike', '%gmail.com');
// still later...
return gmailUsers.where('email_confirmed', true);
一个人为的例子,但在处理不那么琐碎的需求时它可以非常有表现力。
我知道这个 post 有点旧,但我同意混合方法。在某些情况下,查询构建器语法会为正在编写的“错误”查询提供良好的反馈,这很好。
另一方面,我有一些我认为使用构建器编写会变得过于冗长的查询,所以我使用 .raw
。这是我认为保持 .raw
格式的查询示例。
select
s.client_id,
s.package_id,
p.products as pp,
s.products as sp
from (
# grouped subscribed products
select
client_id,
package_id,
group_concat(product_id order by product_id) as products
from subscriptions where package_id is not null
group by client_id, package_id) as s
inner join (
# grouped package products
select
package_id,
group_concat(product_id order by product_id) as products
from package_products
group by package_id) as p
on p.package_id = s.package_id where p.products <> s.products
order by s.client_id
我当然可以使用生成器,但我发现原始 SQL 使用嵌套选择更容易掌握。我还创建了一个抽象 class 以简化为微型 ORM。
class Table {
constructor() {
// nothing
}
static tableName = null;
/**
* Find by id
* @param {Integer} userId
* @return {Promise}
*
* Example:
* Table.findById(id).then(result => {
* console.log(result)
* }).catch(err => {
* console.error(err);
* })
*/
static findById(itemId) {
return this.findOneBy({id: itemId});
}
/**
* Generic findBy
* @param {String|Object} column or objcet with keys
* @param {Any} value
*/
static findOneBy(column, value = null) {
return this.findBy(column, value).then(results => {
return results[0];
});
}
/**
* Generic findBy
* @param {String|Object} column or objcet with keys
* @param {Any} value
*/
static findBy(column, value = null) {
return database.getConnection().then(conn => {
const schema = this.schemaName;
const query = conn.select().from(this.tableName);
if (schema){
query.withSchema(schema);
}
if (typeof column === 'object '&& !Array.isArray(column) && value === null) {
for (const col in column) {
query.where(col, column[col]);
}
} else {
query.where(column, value);
}
return query;
});
}
}
这允许我使用以下方法创建模型:
class Client extends Table {
static tableName = 'clients';
constructor() {
super();
}
}
Client.findById(1).then(result => {
console.log(result);
}).catch(console.error);
我知道 Knex 有很多好处,这就是我考虑将它用于我的 Node 应用程序的原因。我以前用过它,我真的很喜欢用它来编写原始查询。 (注意:我仍处于 Knex 的学习阶段。)就个人而言,我认为它们使代码看起来比使用基本 SQL 稍微好一些。我的问题就是从这一点开始的,因为也许我的偏好在这里很愚蠢。
我也很想对 Knex 的内置功能发表意见。对于那些喜欢生的人来说,你喜欢他们什么?无论我选择哪种途径,我的目标都是在我的应用程序中保持一致性。
感谢您的意见!
这不是毫无意义的。这在一定程度上取决于您是否在团队环境中工作,还有谁可能必须维护它,以及他们对编写 SQL 查询的舒适程度。请注意,许多可以使用 Knex 完成的事情也可以使用直接数据库驱动程序完成,因此对于许多技术选择,它归结为 personal/team 偏好和易于维护。
即使假设您从不使用查询生成器,Knex 也提供:
- 根据目前的配置比较简单
NODE_ENV
- connection/pool 管理
- 简单的参数化
- 轻松交易
- 轻松迁移和播种
为什么不用.raw
?好吧,这是品尝者的选择,查询构建器并不适合所有人。但是,查询构建器的粉丝会告诉您:
- 当你不处理一堆原始数据时,在数据库后端之间迁移会更容易 SQL
- 许多人发现 Knex 语法更容易阅读,因为能够合理理解 JavaScript 承诺链的人数可能超过理解 SQL 的人数
- 它往往更紧凑
- 它比
.raw
提供了 name/syntax 级别的安全性(如果您使用的是 TypeScript,还提供编译时类型安全和编辑器支持)。
查询构建器也非常适合组合,因此:
const userPhoneNumbers = knex('users').select({ id, email });
// later...
const gmailUsers = userPhoneNumbers.where('email', 'ilike', '%gmail.com');
// still later...
return gmailUsers.where('email_confirmed', true);
一个人为的例子,但在处理不那么琐碎的需求时它可以非常有表现力。
我知道这个 post 有点旧,但我同意混合方法。在某些情况下,查询构建器语法会为正在编写的“错误”查询提供良好的反馈,这很好。
另一方面,我有一些我认为使用构建器编写会变得过于冗长的查询,所以我使用 .raw
。这是我认为保持 .raw
格式的查询示例。
select
s.client_id,
s.package_id,
p.products as pp,
s.products as sp
from (
# grouped subscribed products
select
client_id,
package_id,
group_concat(product_id order by product_id) as products
from subscriptions where package_id is not null
group by client_id, package_id) as s
inner join (
# grouped package products
select
package_id,
group_concat(product_id order by product_id) as products
from package_products
group by package_id) as p
on p.package_id = s.package_id where p.products <> s.products
order by s.client_id
我当然可以使用生成器,但我发现原始 SQL 使用嵌套选择更容易掌握。我还创建了一个抽象 class 以简化为微型 ORM。
class Table {
constructor() {
// nothing
}
static tableName = null;
/**
* Find by id
* @param {Integer} userId
* @return {Promise}
*
* Example:
* Table.findById(id).then(result => {
* console.log(result)
* }).catch(err => {
* console.error(err);
* })
*/
static findById(itemId) {
return this.findOneBy({id: itemId});
}
/**
* Generic findBy
* @param {String|Object} column or objcet with keys
* @param {Any} value
*/
static findOneBy(column, value = null) {
return this.findBy(column, value).then(results => {
return results[0];
});
}
/**
* Generic findBy
* @param {String|Object} column or objcet with keys
* @param {Any} value
*/
static findBy(column, value = null) {
return database.getConnection().then(conn => {
const schema = this.schemaName;
const query = conn.select().from(this.tableName);
if (schema){
query.withSchema(schema);
}
if (typeof column === 'object '&& !Array.isArray(column) && value === null) {
for (const col in column) {
query.where(col, column[col]);
}
} else {
query.where(column, value);
}
return query;
});
}
}
这允许我使用以下方法创建模型:
class Client extends Table {
static tableName = 'clients';
constructor() {
super();
}
}
Client.findById(1).then(result => {
console.log(result);
}).catch(console.error);