如何使用Bookshelf.js正确更新模型?

Jas*_*n C 13 javascript node.js bookshelf.js

我确定我错过了一些东西,但我发现Bookshelf API对我来说是无情的混淆.这是我想要做的:

  • 我有一个模型调用Radio了一个应用程序分配的字符串主键serial,并且为了这个例子,有两个名为example1和的字段example2.我idAttribute: 'serial'在模型定义中指定了自定义ID .
  • 我正在尝试使用Bookshelf执行upsert(不直接使用Knex,在我的实际应用程序中查询变得相当复杂).
  • 我有插入案例工作,但似乎无法使更新案例工作.
  • 为简单起见,我现在不关心交易或原子性.我很满意得到一个简单的选择→插入/更新工作.

特别是在这个例子中:

  • 在插入集example1example2.
  • 在更新设置example1,并留下example2不变.

所以我在Bookshelf模型中有这样的东西,作为类(即"静态")方法("info"有字段"serial","example1"和"example2"):

insertOrUpdate: function (info) {
    return new Radio({'serial':info.serial}).fetch().then(function (model) {
        if (model) {
            model.set('example1', info.example1);
            return model.save({}, {
                method: 'update',
                patch: true
            })
        } else {
            return new Radio({
                serial: info.serial,
                example1: info.example1,
                example2: info.example2
            }).save({}, {
                method: 'insert'
            })
        }
    }).then(function (model) {
        console.log("SUCCESS");
    }).catch(function (err) {
        console.log("ERROR", err);
    });
}
Run Code Online (Sandbox Code Playgroud)

示例电话:

Radio.insertOrUpdate({
    serial: ...,
    example1: ...,
    example2: ...
})
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,虽然"插入"案例有效,但"更新"案例失败了:

ERROR { Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where `serial` = '123223'' at line 1
Run Code Online (Sandbox Code Playgroud)

在打开Knex调试时很明显,生成的查询缺少set子句:

update `radios` set  where `serial` = ?
Run Code Online (Sandbox Code Playgroud)

现在,我专注于书架文档的fetchsave,如果我在错误的方向我率领我不知道.

我知道我使用的API错了,但我无法理解.我注意到/必须做的一些奇怪的事情才能让它进入半工作状态:

  • 我不明白第一个参数save.这是有意义的我,如果保存是一个静态的方法Model,但事实并非如此.它是一个实例方法,您已经可以将属性传递给Model构造函数(例如,new X(a:1).save({a:2})意味着什么......?),并且您已经set可以在保存之前设置属性.所以我无法理解这一点.我必须{}作为占位符传递给我指定选项.

  • 有这个forge东西,但我不确定它的目的是什么,因为你已经可以将属性传递给Model构造函数(除非作者发现一些好处X.forge({a:1})new X({a:1})...?).

  • 我发现由于明显的Bookshelf怪癖,我必须明确指定要保存的方法:Bookshelf基于它的方法选择isNew(),但isNew()总是true在你将id传递给模型构造函数时,你必须在应用程序分配中执行ID案例.因此,对于应用程序分配的ID,Bookshelf将始终执行"插入",因为它始终认为模型"是新的".所以你必须强制该方法"更新"...这只会增加我的Bookshelf混淆.

无论如何,我该如何正确地做到这一点?如何使此插入和更新工作?

更重要的是,这在哪里记录?本着善意,我认为它某处清楚地记录下来,我现在看不到树木的森林,所以我真的很欣赏文档中的一些方向,而不是直接回答,因为我确实需要弄清楚这一点.我花了很多时间在Bookshelf而不是实际的开发上,以至于我几乎希望我从一开始就坚持直接进行SQL查询.

fla*_*usa 6

这是一个有趣的,我花了一些时间来了解发生了什么.

正如您似乎已经发现的那样,关于该选项的save()方法文档说明了patch

仅保存参数中提供的属性以进行保存.

所以你只需要将代码更改为

if (model) {
    model.set('example1', info.example1);
    return model.save();
}
Run Code Online (Sandbox Code Playgroud)

set保存属性.

所有属性都会进入update声明,甚至是id!

这是ORM的常见行为,其基本原理是,如果我们从一个事务中获取数据并从另一个事务中保存(坏的,不好的做法!),那么其他客户端可能已经更改了数据.因此,仅保存部分属性可能会导致状态不一致.

但该patch属性的存在违反了这一概念.所以Bookshelf可以通过以下方式改进:

  • 简单地弃用该patch选项.(我更喜欢那个)
  • 由于Bookshelf模型会跟踪已更改的属性,因此我认为在这方面使更新变得更加智能应该是微不足道的.这种变化也可能导致patch期权的弃用.
  • 另一种方法可能是使patch语义与更改的属性相关,而不仅仅是提供的属性save().但不幸的是,这种变化可能会破坏一些用例.
  • 或者最后引入一个选项来处理所有已更改的属性.但那感觉很麻烦.