这个答案既是对问题的回答,也是分析问题的教程。
第 1 步 - 简化和隔离
让我们从根本上简化,直到找到缺失的步骤。让我们从您拥有的最简单的实体类型开始……最多具有 2 到 5 个属性的实体类型。没有吗?补一张吧减少Manufacturer
只是“id”和“name”。我们首先要尝试把机制搞清楚。
您没有在服务器上使用任何微风组件。美好的。选择提供该测试实体数据的服务器端点。让该端点仅通过一个实例传递一个 JSON 数组。向我们展示到达客户端的 JSON...整个 JSON 有效负载,与到达网络时完全相同。内容应该简短;如果不是,那么你的简化还不够。
然后我们可以弄清楚您是否需要 JsonResultsAdapter 以及如果需要的话它应该是什么样子。
向我们展示您填充的确切顺序metadataStore
带有 EntityType、ctor 和初始值设定项。坦率地说,在第一个工作之前,我宁愿没有构造函数或初始化程序。
您如何确保EntityManager
您创建的是使用该商店吗?我们需要查看您的配置代码以及您如何更新EntityManager
并用它来查询端点。
如果您遵循我的建议,就不会有太多代码。也许有二十行。 JSON feed 应约为 10 行。如果您达不到这些数字,则说明您的简化程度还不够。
第 2 步 - 查看更简单的示例
现在您已经重新编写了该示例,我更好地了解了该去哪里查找。
有两件事突然出现在我眼前:
- 来自服务器的 JSON 结果
- The
camelCase
命名约定
来自服务器的 JSON
让我们漂亮地打印您提供的 JSON 结果并讨论它们:
{
"id": "141",
"name": "Trek",
"website": "http:\/\/www.trekbikes.com\/",
"approved": "1",
"user_id": "3"
}
Breeze 不知道如何处理该 JSON 对象,因为它缺少类型信息。对于微风来说,它只是一个任意的物体,也许是投影的结果。
将其与访问 DocCode Web API 的查询的 JSON 结果进行比较。这是为查询生成的 URL:
>http://localhost:47595/breeze/northwind/Suppliers/?$top=1
这是(缩写的)JSON 结果
[
{
"$id":"1",
"$type":"Northwind.Models.Supplier, DocCode.Models",
"SupplierID":1,
"CompanyName":"Exotic Liquids"
}
]
默认情况下Breeze 客户端需要已序列化的数据JSON.NET,ASP.NET 中的默认序列化程序。
JSON.NET 有效负载是一个节点或节点数组。 JSON.NET 添加了自己的$id
and $type
每个节点的属性。
我想把你的注意力集中在$type
您可能会将其识别为 .NET 类型的全名(带有命名空间的类、程序集名称)。
你可以逃脱没有$id
财产。
$id 是一个自动递增的序列化键。通常,同一个对象会在有效负载中出现多次。 JSON.NET 没有重复内容,而是用一个简单的节点代替,例如{$ref: #}
where #
指的是$id
较早的节点。这种方法既减少了有效负载大小,又打破了循环引用。
不过Breeze真的很期待$type
财产。这就是它将 JSON 对象/节点连接到元数据中的类型的方式。如果您的制造商示例节点有一个,它可能如下所示:
"$type": "StackAndReach.Manufacturer, MyModel"
我不知道你如何在服务器上序列化数据。您似乎正在使用 JSON.NET 以外的其他东西。
太棒了。我只是告诉你 Breeze 默认情况下是如何工作的;它对.NET 非常友好。但 Breeze 不需要 .NET。它是一个纯 JavaScript 库。你只需要告诉它你想要什么。
Use 输入(...)
你能做的最简单的事情就是add toType您的查询.
var query = breeze.EntityQuery.from('Manufacturers')
.where( ... )
.toType( 'Manufacturer' );
通过这种方式,您可以明确声明“制造商”端点返回的顶级节点包含Manufacturer
您在元数据中描述的类型。
我敢打赌这会立即对你有用(一旦你修复命名约定问题如下面所描述的)。
这是一种有效的方法,但它有几个缺点。我提两点:
您必须记住将其添加到每个查询中。
它只适用于顶级实体; if 不适用于嵌套实体,例如应用时返回的.expand()
clause.
我更喜欢教 Breeze 客户端如何自行解释 JSON 结果......使用自定义JsonResultsAdapter
.
自定义 JsonResultsAdapter
查看微风埃德蒙兹样本其中 Breeze 客户端使用来自 Edmunds 车辆信息服务的数据。
Edmunds 服务器发送完全不同类型的 JSON 有效负载来响应查询。这是一个片段:
{
"makeHolder":[
{
"id":200347864,
"models":[
{
"link":"/api/vehicle/am-general/hummer",
"id":"AM_General_Hummer",
"name":"Hummer"
}
],
"name":"AM General",
"niceName":"amgeneral",
"manufacturer":null,
"attributeGroups":{
}
},
... more ...
]
}
No $type
那里也有。 Breeze 开发者做了什么?他写了一个自定义 Breeze JsonResultsAdapter它在文件中应用程序/jsonResultsAdapter.js.
尽管只有 40 行,但我不打算在这里重现该文件。我想让你读一下jsonResultsAdapter文档,拉下 Edmunds 示例,然后自己阅读。
我将总结它的作用以及它是如何工作的。微风呼唤你的jsonResultsAdapter
首先是当它收到 JSON 有效负载时,然后是当它处理该有效负载中的每个节点时。您的工作是告诉 Breeze 如何处理该节点,您可以通过调整节点本身并返回描述该节点的元对象来完成。
这是一个片段:
>if (node.id && node.models) {
// move 'node.models' links so 'models' can be empty array
node.modelLinks = node.models;
node.models = [];
return { entityType: "Make" }
}
此代码片段中有三个活动:
- 识别节点的内容(
if ...
)
- 调整节点值(出于任何对您有意义的原因)
- 组合并返回“元”对象结果。
专注于#3。这就是开发人员告诉 Breeze“将这个节点变成一个Make
entity.
结构型式匹配
你可能会说,“嘿沃德,Manufacturer
实体类型与 JSON 对象结构完全匹配。微风应该将其识别为Manufacturer
."
Breeze 不会通过匹配类型结构来预测实体类型。我也不认为它应该......因为不同类型通常共享相同的结构。例如:我有一个StatusCode
and ProductCode
两者都是实体类型{ id: int, name: string}
。我们还有很多其他增强功能需要改进;处理类型歧义并不是我们的首要任务。
命名约定
最后,让我们回到我看到的另一个问题。
Your configureBreezeManager
方法开始:
breeze.NamingConvention.camelCase.setAsDefault();
您已将默认命名约定从“same-on-client-and-server”更改为“pascalCase-on-client/CamelCase-on-server”。
通过切换到camelCase
惯例,你告诉 Breeze 客户端属性foo
应发送到服务器Foo
.
这是正确的做法吗?如果您的服务器需要 CamelCase 属性名称,那就是这样。但是,根据 JSON 负载中的属性名称,服务器也需要使用 CamelCase。客户端和服务器上的属性名称相同。如果微风向制造商发送了带有Name
属性值而不是name
适当的价值。
保留微风默认值,“不执行任何操作”约定。不要覆盖它。从您的文件中删除 pascalCase 约定行configureBreezeManager
.
保存更改
我们一直在讨论查询结果。我们根本没有讨论如何将更改保存回服务器。
我确信您有自己的协议(类似 ReST 的东西?)和序列化格式。这是一个完全不同的讨论。我们不要在这个 Stack Overflow 问题中讨论这个问题。我只是提醒您,您可能很快就会为这个问题摸不着头脑。