我正在努力调试此错误,因为虽然它一直报告,但应用程序的行为与预期一致。希望指出它的意义以及我如何调试其来源。
道歉,但是,由于我得到了理想的结果,我不确定要提供的其他信息。
更新
我已经创建了这个问题的副本,并试图将代码集中在问题上。即使正确更新数据库,也会一致地抛出错误。代码中有一个saveChanges,它使用Breeze Todo示例中dataservice.js的保存功能。 SaveOptions.allowConcurrentSaves为false。
完全无法解释它,并查看了我的EF代码,看看我是否犯了一个明显的错误,但看不到它。发送到WebAPI SaveChanges方法的包看起来也正确(正确填充了ID等)。
https://github.com/DazWilkin/BreezeJS.ScoreIssue
2月6日更新
韦德的有用答案仍然没有解决这个问题。不幸的是,除非我能理解它是错误的或者知道这是一个错误,否则我将不得不放弃在这个项目中使用Breeze并恢复到糟糕的,简单的旧AJAX调用。
似乎问题围绕服务器在保存更改时返回归零的GUID。该方法不返回任何错误。我很高兴得知这是我实体模型中的一个错误,但我很怀疑。
这是失败:
breeze.debug.js:11954
var ix = this._indexMap[tempValue];
if (ix === undefined) {
throw new Error("Internal Error in key fixup - unable to locate entity");
}
当代码到达这一点时,this._indexMap的值是正确的,并且是:
{"bcb6e670-00fc-469d-8531-5767f40bf3c1":0}
但是tempValue的值(由服务器的Web API调用返回)是错误的:
00000000-0000-0000-0000-000000000000
realValue是正确的,是:
1093b975-7686-4621-8336-77c38ed36de0
备份堆栈。以下是来自AJAX调用的结果,breeze.debug.js:12574。看到tempValue在从服务器/ WebAPI调用返回时归零。 realValue是正确的。这是数据库包含的内容。该行没有问题地添加到表中。
"KeyMappings": [
{
"$id": "4",
"$type": "Breeze.WebApi.KeyMapping, Breeze.WebApi",
"EntityTypeName": "...Score",
"TempValue": "51877f5b-811f-4260-bd5b-cf9965159597",
"RealValue": "92b73b8a-8b33-45cd-9822-ca7c0c5d5d9a"
},
{
"$id": "5",
"$type": "Breeze.WebApi.KeyMapping, Breeze.WebApi",
"EntityTypeName": "...PropertyValue",
"TempValue": "00000000-0000-0000-0000-000000000000",
"RealValue": "1093b975-7686-4621-8336-77c38ed36de0"
}
],
验证saveBundle中收到的服务器端。注意,在服务器上收到的两个实体的ID都有有效的GUID ID。
"entities": [
{
"ID": "51877f5b-811f-4260-bd5b-cf9965159597",
...
"entityAspect": {
"entityTypeName": "Score:...",
"entityState": "Added",
"originalValuesMap": {},
"autoGeneratedKey": {
"propertyName": "ID",
"autoGeneratedKeyType": "Identity"
}
}
},
{
"ID": "bcb6e670-00fc-469d-8531-5767f40bf3c1",
...
"entityAspect": {
"entityTypeName": "PropertyValue:...",
"entityState": "Added",
"originalValuesMap": {},
"autoGeneratedKey": {
"propertyName": "ID",
"autoGeneratedKeyType": "Identity"
}
}
}
],
不出所料,在breeze.debug.js:10494 saveBundleStringified中创建的AJAX调用发送给服务器的值是正确的,与服务器接收的值相同(不会重现,但我向你保证)
而且,从我的代码中,当调用saveChanges时,
manager.getChanges().length == 2
manager.getChanges()[0].ID() == "51877f5b-811f-4260-bd5b-cf9965159597" (Score)
manager.getChanges()[1].ID() == "bcb6e670-00fc-469d-8531-5767f40bf3c1" (PropertyValue)
并且,正如预期的那样,这些匹配在服务器接收的saveChanges期间实体ID的(temp)值...
我做错了什么?如果我有头发,我会把它撕掉!
答案 0 :(得分:5)
我已经解决了。
我的不一致应用(!)约定是在代码优先类型上使setter内部/私有。我说不一致,因为在觉得我已经用尽所有可能性之后,我发现PropertyValue类型,即发起错误的类型,有一个内部集。
删除了这个并重建了解决方案后,问题就解决了!
所以:
public Guid ID { get; internal set; }
应该是:
public Guid ID { get; set; }
答案 1 :(得分:3)
根据您对谢尔盖答案的评论,您可能在保存操作完成之前尝试对已更改的实体执行某些操作。
这些实体保持更改状态...通常使用临时主键和外键...直到服务器报告成功保存。
在保存成功之前,您可能不应该触摸它们。正如Sergey所说,您应该在保存成功回调中找到保存后的处理。
return manager.saveChanges() .then(saveSucceeded) .fail(saveFailed);
您不应将saveChanges
调用包装在jQuery Deferred
中。这是浪费时间和复杂性。 EntityManager.saveChanges
方法返回调用者可以使用的承诺。视图模型可以添加自己的成功和失败回调
dataservice.saveChanges() .then(hooray) .fail(sadTrombone);
我在您的代码中注意到您使用 Todo 示例中的time-delay approach来防范非法并发保存。
这种方法实际上只适用于演示。如果您的视图模型需要在保存成功时执行某些任务,那么它将无法正常工作。它不起作用,因为dataservice无法使用时间延迟方法向视图模型返回承诺。
如果您需要非屏蔽保存,请查看“酷风”部分下“Save Queuing”主题中所述的“Concurrent Saves”插件。
在查看代码时,我无法注意到 scoreissue.1.0.ts 中的实体工厂方法有点冗长。你写的是:
export function Business(manager, o: IBusiness) { var business = manager.metadataStore.getEntityType("Business").createEntity(); business.ID(breeze.core.getUuid()); business.Name(o.name); manager.addEntity(business); return business; }
可能很简单:
export function Business(manager, o: IBusiness) { return manager.createEntity("Business", { ID: breeze.core.getUuid(), Name: o.name, }); }
EntityManager.createEntity
快捷方式是新的,因为您编写了此代码,所以不要错过它。
[错误的方向。保留理解DazWilkin评论问题是在客户端。]
这是在哪里生成的?在服务器上?如果是这样,您可以继承EFContextProvider并覆盖SaveChangesCore
。调用base.SaveChangesCore
并在其周围放置一个try / catch。检查saveMap
参数。 EFContextProvider是开源的;我开始在这里挖掘。
答案 2 :(得分:1)
当涉及密钥生成的多个同时保存请求同时挂起时,可能会发生此错误。此错误仅在保存期间发生吗?如果是这样,请尝试将SaveOptions.allowConcurrentSaves设置为false。如果这导致出现不同的错误(并发保存错误),那么您的问题肯定与并发保存有关。
希望这有帮助。