【发布时间】:2015-02-27 01:57:59
【问题描述】:
问题
EntityManager.saveChanges时出现“TypeError: object is not a function”错误。在微风向服务器发送任何内容之前出现错误。当我阅读(长)堆栈跟踪时,我看到错误是在名为
InitializeEntityPrototype.prototype.getProperty的 Breeze 方法中引发的。
您可能会在其他地方遇到此错误;这恰好是我今天发现它的地方。
原因
请注意,我的应用程序使用 Knockout (ko)。这意味着我的实体模型由轻量级“ko”模型适配器管理,该适配器期望 每个数据属性 都是 ko.observable(@ 987654323@ 或observableArray)。这意味着您的属性值被实现为函数,而不是原始数据类型、数组或对象。
Breeze 使用可观察属性初始化我的实体,因此我不必自己动手。但由我决定在我的代码中设置实体模型时保留这些可观察对象。
ko 编程中最常见的错误之一是设置属性而不是调用属性设置器。
todo.Description("foo"); // Correct ... call the ko.observable assignment function
todo.Description = "foo"; // WRONG ... wipes out the observable function !!!
当我错误地将“foo”分配给todo.Description 时,可观察函数就消失了……Breeze 监视该属性更改的能力也消失了。
我的数据绑定 HTML 控件似乎可以继续工作。 Knockout 不必绑定到 observable;它将愉快地绑定到原始数据值。但现在这变成了一次性只读绑定。该属性不再是可观察的。对该属性的后续更改将不会传播到屏幕。
换句话说,我的错误分配会导致 UI 行为出现静默错误。
但是当 Breeze 尝试处理该属性时,我的错误并没有消失。 Breeze 假设实体数据属性是一个 ko 函数。 Breeze ko 模型适配器不需要检查......它只是调用它假定的函数。这是(内部)实体getProperty 的实现:
proto.getProperty = function (propertyName) {
return this[propertyName]();
};
如果this[propertyName] 不是函数,您就会明白为什么会抛出异常。
对我来说可悲的是,错误很可能是在 Breeze 操作的内部深处引发的。错误消息“对象不是函数”(或类似的东西)可能是关于任何东西的。我不太可能建立联系。
这个 S.O.这个问题提醒您寻找这个特定的原因。
怎么办?
这显然是我的错。现在我必须找到我分配实体属性的位置而不是调用函数......并修复它。
我的搜索取决于知道属性名称。当前的错误消息没有告诉我名称。所以我必须对代码进行断点并在抛出错误时捕获它。
一个“简单”的权宜之计是在 breeze.debug.js 中使用 try/catch 版本临时修补此方法。
- 在编辑器中打开 breeze.debug.js
- 找到“
return this[propertyName]();” -
改成这样:
proto.getProperty = function(propertyName) { try { return this[propertyName](); } catch (err) { debugger; err.message = propertyName + ' is not a ko function; did you wipe it out by assignment?\n' + (err.message || ''); throw err; } } 在打开开发者工具的情况下再次运行应用
它应该停在debugger 行,在那里您将了解属性名称和所涉及的实体。
Breeze 是否应该提供更丰富的错误消息?
如果 Breeze 为我撰写此消息,那就太好了。事实上,该团队正在考虑这样做。
主要障碍是性能。 getProperty 和 setProperty 方法处于热路径上。他们经常被调用,尤其是在查询结果实现期间。 Breeze 团队对这个敏感领域的额外逻辑持谨慎态度。我们不希望每个人都付出高昂的代价来捕捉开发人员错误,至少不是在生产(缩小)Breeze 库中。
让 Breeze 团队有时间解决这个问题。
【问题讨论】:
-
您先生应该得到更多的支持。你救了我的……你知道吗。
标签: knockout.js breeze