【问题标题】:Breeze EntityManager cache not cleared after successful server save成功服务器保存后未清除 Breeze EntityManager 缓存
【发布时间】:2014-05-03 02:20:54
【问题描述】:

几天来,我一直在尝试让 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 键映射中合并,但不清除缓存,所以下次我进行另一个实体更改时,它仍然有第一个已经持久化到服务器的更改和新的更改。谁能告诉我我没有从 Rails 方面做出回应,这让 Breeze EntityManager 不满意?我正在尝试追踪 15k 行代码,但不能说我是 JS 忍者。

【问题讨论】:

  • 加载一个使用 saveChanges 的示例应用程序并检查响应以查看是否有任何设置可能会更快。
  • 不确定我是否完全理解@PWKad。我已经运行了 Breeze ruby​​ SPA 应用程序,但是这个应用程序略有不同,因为我没有节省每次更改。我基本上只是提供一个服务器到客户端名称的映射,但希望其他一切都能正常工作。
  • 我提到它可能更容易抓取并运行使用 Web API 实现 saveChanges 的示例之一,以查看返回 JSON 的样子,但看起来 Ward 已经在下面为您复制了返回.

标签: ruby-on-rails ruby angularjs breeze


【解决方案1】:

我们确实需要向人们展示如何为他们拥有的任何服务构建数据服务适配器。

在这种情况下,您似乎选择在 Web API 上用 C# 实现 SaveChanges 方法。换句话说,您选择模拟开箱即用的 Breeze 协议。这很酷!也很重要,所以向你致敬。

我认为您保存响应中的实体 JSON 缺少的是 EntityType 名称。 Breeze 在不知道它们的类型的情况下找不到相应的缓存实体,因此无法更新它们的更改状态。

同样,因为您决定使用默认的 Web API 数据服务适配器,所以您需要返回适配器期望的响应。该适配器定义了一个“jsonResultsAdapter”,它期望每个 JSON 实体数据对象都有一个 $type 属性来指定完整的类型名称 (namespace.typename)。

在您的示例中,我认为您想返回

...
"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:#namespace”。这是数据服务适配器的 jsonResultsAdapter ... 的工件,您可以更改它以更好地适应您的 Rails 实现。这一切都不是一成不变的。我只是报告这些适配器在交付时的作用。

您可以忽略$type 值中的程序集名称(“,Todo-Angular”);微风不在乎。

请注意,已删除的“Cheese”实体与其所有内容一起返回。我打赌你不必那样做。您可以返回一个精简版本,让客户知道 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
} 

【讨论】:

  • 谢谢@Ward。有用!如果有一些关于构建数据服务适配器的教程来强调适配器必须满足的要求,那就太好了。我可能只会实现 Web API 在 Rails 中的一小部分功能,但会确保与大家分享。
  • 我知道!我知道!对您来说是个好消息……我的一些朋友正在研究 Rails 适配器和 Rails GEM,它将为服务器端带来 Breeze 感知,因此您可以使用 OData 查询语法和批量保存。还有一个正在开发中的服务器数据服务适配器。
猜你喜欢
  • 2021-07-14
  • 2015-07-03
  • 1970-01-01
  • 2019-01-01
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
  • 2018-08-08
  • 1970-01-01
相关资源
最近更新 更多