我确定我遗失了一些东西,但我发现Bookshelf API对我来说是无情的混淆。这就是我要做的事情:
Radio
的模型,其中包含一个名为serial
的应用程序指定字符串主键,为了本示例的目的,有两个名为example1
和example2
的字段。我已在模型定义中使用idAttribute: 'serial'
指定了自定义ID。特别是在这个例子中:
example1
和example2
。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` = ?
现在,我专注于fetch
和save
的书架文档,并且我想知道我是否朝错误的方向前进。
我知道我错误地使用了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查询。
答案 0 :(得分:6)
这是一个有趣的问题,花了我一些时间来了解发生了什么。
正如您似乎已经发现的那样,关于save()
选项的patch
方法documentation声明它
仅保存参数中提供的属性以进行保存。
所以你只需要将代码更改为
if (model) {
model.set('example1', info.example1);
return model.save();
}
将保存set
属性。
但 但是 但
所有属性都会进入update
语句,甚至是id
!
这是ORM的常见行为,其基本原理是,如果我们从一个事务中获取数据并从另一个事务中保存(坏的,不好的做法!),那么其他客户端可能已经更改了数据。因此,仅保存部分属性可能会导致状态不一致。
但patch
属性的存在违反了这个概念。所以Bookshelf可以改进:
patch
选项即可。 (我更喜欢那个)patch
选项的弃用。patch
语义与更改的属性相关,而不仅仅是save()
上提供的语义。但不幸的是,这种变化可能会破坏一些用例。答案 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获得了什么。必须有一个更好的方法。