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

时间:2017-01-28 21:02:09

标签: javascript node.js bookshelf.js

我确定我遗失了一些东西,但我发现Bookshelf API对我来说是无情的混淆。这就是我要做的事情:

  • 我有一个名为Radio的模型,其中包含一个名为serial的应用程序指定字符串主键,为了本示例的目的,有两个名为example1example2的字段。我已在模型定义中使用idAttribute: 'serial'指定了自定义ID。
  • 我尝试使用Bookshelf执行upsert(不直接使用Knex,在我的实际应用程序中查询变得相当复杂)。
  • 我已经将插入案例工作了,但似乎无法让更新案例有效。
  • 为简单起见,我现在并不关心交易或原子性。我很满意得到一个简单的选择→插入/更新来工作。

特别是在这个例子中:

  • 插入集example1example2
  • 在更新集example1上保持example2不变。

所以我在Bookshelf模型中得到类似的东西,作为一个类(即"静态")方法(" info"有字段" serial&# 34;," 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);
    });
}

示例电话:

Radio.insertOrUpdate({
    serial: ...,
    example1: ...,
    example2: ...
})

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

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

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

update `radios` set  where `serial` = ?

现在,我专注于fetchsave的书架文档,并且我想知道我是否朝错误的方向前进。

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

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

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

  • 我发现由于明显的Bookshelf怪癖,我必须明确指定要保存的方法:Bookshelf基于new X({a:1})选择方法,但isNew()总是isNew()当您将id传递给模型构造函数时,您必须在应用程序分配的ID情况下执行此操作。因此,对于应用程序分配的ID,Bookshelf将始终执行"插入"因为总是认为模型"是新的"。因此,您必须强制该方法更新" ...这只会增加我的Bookshelf混淆。

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

更重要的是,这在哪里记录?本着诚意,我认为 在某处清楚地记录下来,我现在无法看到森林中的森林,所以我真的很欣赏文档中的一些方向。甚至不仅仅是一个直接的答案,因为我确实需要弄明白这一点。我已经花了很多时间在Bookshelf而不是实际的开发上,以至于我几乎希望我从一开始就坚持直接的SQL查询。

2 个答案:

答案 0 :(得分:6)

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

正如您似乎已经发现的那样,关于save()选项的patch方法documentation声明它

  

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

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

if (model) {
    model.set('example1', info.example1);
    return model.save();
}

将保存set属性。

但是

所有属性都会进入update语句,甚至是id

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

patch属性的存在违反了这个概念。所以Bookshelf可以改进:

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

答案 1 :(得分:1)

经过几次猜测后,我似乎已经开始工作了,但我不知道这是不对的,或者我怎么能在没有猜测的情况下确定这一点,而且我绝对不会支持它的正确性。

基本上我可以通过将“更新”案例修改为:

来使其工作
  • 将属性传递给save作为其第一个参数,而不是将其设置为set

导致最终解决方案:

insertOrUpdate: function (info) {
    return new Radio({'serial':info.serial}).fetch().then(function (model) {
        if (model) {
            // pass params to save instead of set()
            var params = { 'example1' : info.example1 }
            return model.save(params, {
                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);
    });
}

我仍然不确定forge如何适合这里,或者“插入”案例中save的第一个参数应该达成什么协议。

更重要的是,我现在还不完全确定set的用途。 ORM框架的主要好处之一是假设使这种东西变得透明(即“保存”正常工作,同时让你在不考虑它的情况下使用模型,而且你不必拥有它知道你在“保存”时发生了什么变化 - 我应该能够提前知道未知的任意代码set然后能够保存它而不知道改变了什么,但它看起来我不能),所以我不确定我在这里从Bookshelf获得了什么。必须有一个更好的方法。