我现在已经尝试了几天让Breeze 1.4.9以与Breeze Ruby SPA样本不同的方式使用rails后端。我宁愿发送批量保存更改,而不是尝试在每次实体更改时向服务器发送RESTful调用。为此,我编写了一个rails控制器/模型方法,它将解析Breeze SaveChanges POST中的所有不同实体并采取相应措施。一切都很好,除了对SaveChanges POST的响应似乎并不能满足Breeze和EntityManager.hasChanges()的所有检查,即使在成功处理响应后仍然如此。
这是一个典型的周期: Breeze请求我手工制作的元数据并解析它:
{
"metadataVersion": "1.0.5",
"namingConvention": "rubyNamingConvention",
"localQueryComparisonOptions": "caseInsensitiveSQL",
"dataServices": [
{
"serviceName": "breeze\/Breeze\/",
"hasServerMetadata": true,
"jsonResultsAdapter": "webApi_default",
"useJsonp": false
}
],
"structuralTypes": [
{
"shortName": "VarianceReason",
"namespace": "Icon",
"autoGeneratedKeyType": "Identity",
"defaultResourceName": "VarianceReasons",
"dataProperties": [
{
"name": "id",
"dataType": "Int32",
"isNullable": false,
"defaultValue": 0,
"isPartOfKey": true,
"validators": [
{
"name": "required"
},
{
"name": "int32"
}
]
},
{
"name": "name",
"dataType": "String",
"isNullable": false,
"defaultValue": "",
"maxLength": 256,
"validators": [
{
"name": "required"
},
{
"maxLength": 256,
"name": "maxLength"
}
]
},
{
"name": "createdAt",
"dataType": "DateTime",
"isNullable": false,
"defaultValue": "1900-01-01T08:00:00.000Z",
"validators": [
{
"name": "required"
},
{
"name": "date"
}
]
},
{
"name": "updatedAt",
"dataType": "DateTime",
"isNullable": false,
"defaultValue": "1900-01-01T08:00:00.000Z",
"validators": [
{
"name": "required"
},
{
"name": "date"
}
]
}
]
}
],
"resourceEntityTypeMap": {
"VarianceReasons": "VarianceReason:#Icon"
}
}
我在Breeze中进行实体更改,当我调用em.SaveChanges()时,它会将下面的帖子发送到rails:
{
"entities":[
{
"id":-1,
"name":"anyuthingasd",
"created_at":"1900-01-01T08:00:00.000Z",
"updated_at":"1900-01-01T08:00:00.000Z",
"entityAspect":{
"entityTypeName":"VarianceReason:#Icon",
"defaultResourceName":"VarianceReasons",
"entityState":"Added",
"originalValuesMap":{
},
"autoGeneratedKey":{
"propertyName":"id",
"autoGeneratedKeyType":"Identity"
}
}
}
],
"saveOptions":{
}
}
然后Rails回复:
{
"KeyMappings":[
{
"EntityTypeName":"VarianceReason:#Icon",
"TempValue":-1,
"RealValue":16
}
],
"Entities":[
{
"id":16,
"name":"anyuthingasd",
"created_at":"2014-05-02T14:21:24.221Z",
"updated_at":"2014-05-02T14:21:24.221Z",
"Entity":null
}
]
}
Breeze然后合并新的id键映射但不清除缓存,所以下次我进行另一个实体更改时,它仍然有第一个已经持久保存到服务器的更改和新的更改。任何人都可以告诉我,我没有从轨道方面做出响应,这使得Breeze EntityManager不满意吗?我试图追踪15k行代码,但不能说我是JS忍者。
答案 0 :(得分:2)
我们确实需要向人们展示如何为他们所拥有的任何服务构建数据服务适配器。
在这种情况下,您似乎选择在Web API上实现C#中的SaveChanges
方法。换句话说,您已选择模拟开箱即用的Breeze协议。太酷了!对你来说,非平凡的事情也是如此的荣耀。
我认为保存响应中实体JSON中缺少的是 EntityType名称。 Breeze无法在不知道其类型的情况下找到相应的缓存实体,因此无法更新其更改状态。
同样,由于您已决定使用默认的Web API数据服务适配器,因此您需要返回适配器所需的响应。该适配器定义了一个" jsonResultsAdapter"期望每个JSON实体数据对象具有指定完整类型名称(namespace.typename)的$type
属性。
在您的示例中,我认为您想要返回
...
"Entities":[
{
"$type": "Icon.VarianceReason",
"id":16,
"name":"anyuthingasd",
"created_at":"2014-05-02T14:21:24.221Z",
"updated_at":"2014-05-02T14:21:24.221Z",
}
]
我怀疑您可能无法轻松访问具有Web API的服务器,该服务器可以显示默认适配器的保存响应。因此,我已粘贴到Todo应用的saveChanges
请求和响应下方,以便更改集包含新的,已修改的和已删除的TodoItem
。
以下是对" SaveChanges"的POST请求的有效负载。端点。它可能比你需要的更冗长(比我需要的更冗长)。仅举几个例子," autoGeneratedKey"对服务器没什么兴趣。
我只是向您展示默认数据服务适配器发送的内容。有一天,你会按照你想要的方式自己写。现在我觉得发送太多crappola没有坏处...只要你乐意在Rails端忽略它: - )
{
"entities": [
{
"Id": 5,
"Description": "Cheese",
"CreatedAt": "2012-08-22T09:05:00.000Z",
"IsDone": true,
"IsArchived": false,
"entityAspect": {
"entityTypeName": "TodoItem:#Todo.Models",
"defaultResourceName": "Todos",
"entityState": "Deleted",
"originalValuesMap": {
},
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
},
{
"Id": 6,
"Description": "Modified Todo",
"CreatedAt": "2012-08-22T09:06:00.000Z",
"IsDone": false,
"IsArchived": false,
"entityAspect": {
"entityTypeName": "TodoItem:#Todo.Models",
"defaultResourceName": "Todos",
"entityState": "Modified",
"originalValuesMap": {
"Description": "Wine"
},
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
},
{
"Id": -1,
"Description": "New Todo",
"CreatedAt": "2014-05-02T17:34:00.904Z",
"IsDone": false,
"IsArchived": false,
"entityAspect": {
"entityTypeName": "TodoItem:#Todo.Models",
"defaultResourceName": "Todos",
"entityState": "Added",
"originalValuesMap": {
},
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": {
}
}
$id
属性是节点计数器。当您重复实体时,它非常有用,因此您不必担心有效负载中的周期或重复的实体数据(具有$ref
属性的对象是重复实体的占位符)。如果您不需要此功能,则可以忽略$id
(并且在保存结果中很少需要它)。
请注意,$type
位于.NET" CSDL"类型格式" namespace.typename",而不是Breeze类型格式" typename:#namename"。这是数据服务适配器jsonResultsAdapter
的工件......您可以更改它以更好地适应您的Rails实现。这些都不是一成不变的。我只是报告这些适配器的功能。
您可以忽略
$type
值中的程序集名称(",Todo-Angular");微风并不关心它。
请注意已删除的"奶酪"实体与其所有内容一起返回。我打赌你不必这样做。你可以放弃返回一个简单的版本,让客户知道Rails得到了消息:
{
"$id": "2",
"$type": "Todo.Models.TodoItem, Todo-Angular",
"Id": 5
},
现在......完整的JSON响应主体:
{
"$id": "1",
"$type": "Breeze.ContextProvider.SaveResult, Breeze.ContextProvider",
"Entities": [
{
"$id": "2",
"$type": "Todo.Models.TodoItem, Todo-Angular",
"Id": 5,
"Description": "Cheese",
"CreatedAt": "2012-08-22T09:05:00.000Z",
"IsDone": true,
"IsArchived": false
},
{
"$id": "3",
"$type": "Todo.Models.TodoItem, Todo-Angular",
"Id": 6,
"Description": "Modified Todo",
"CreatedAt": "2012-08-22T09:06:00.000Z",
"IsDone": false,
"IsArchived": false
},
{
"$id": "4",
"$type": "Todo.Models.TodoItem, Todo-Angular",
"Id": 7,
"Description": "New Todo",
"CreatedAt": "2014-05-02T17:34:00.904Z",
"IsDone": false,
"IsArchived": false
}
],
"KeyMappings": [
{
"$id": "5",
"$type": "Breeze.ContextProvider.KeyMapping, Breeze.ContextProvider",
"EntityTypeName": "Todo.Models.TodoItem",
"TempValue": -1,
"RealValue": 7
}
],
"Errors": null
}