我正在使用Angular和Breeze设置SPA。我一直在从复数网站关注John Papa的热巾教程。我有一个奇怪的问题我认为可能会从我的元数据产生?但最后,我并不确定......
首先,我的API正在运行LAMP堆栈,所以我没有使用EF。我创建了一个元数据端点,我认为它给了我正确的结构。我正在使用breeze.angular.q.js来帮助我从Q到$ q的映射
资源:api / v1 /元数据
{
"metadataVersion": "1.0.5",
"dataServices": [
{
"serviceName": "api/v1/",
"hasServerMetadata": true,
"jsonResultsAdapter": "webApi_default",
"useJsonp": false
}
],
"structuralTypes": [
{
"shortName": "tracks",
"namespace": "MyNamespace",
"dataProperties": [
{
"name": "id",
"nameOnServer": "id",
"maxLength": 36,
"validators": [],
"dataType": "Guid",
"isPartOfKey": true
},
{
"name": "title",
"nameOnServer": "title",
"maxLength": 255,
"validators": [],
"dataType": "String"
},
{
"name": "description",
"nameOnServer": "description",
"maxLength": 0,
"validators": [],
"dataType": "String"
}
]
}
]
}
示例API返回数据如下所示:
资源:api / v1 / tracks
{
"data": [
{
"id": "495f21d6-adfc-40b6-a41c-fc93d9275e24",
"title": "harum",
"description": "Error doloribus ipsam et sunt fugiat."
},
{
"id": "d7b141d2-6523-4777-8b5a-3d47cc23a0fe",
"title": "necessitatibus",
"description": "Voluptatem odit nulla maiores minima eius et."
}
],
"embeds": [
"courses"
]
}
现在用我的所有代码,我实际上是从我的api返回正确的数据。我已经把微风网站上的例子作为我在SO(like this question and great answer from ward)找到的一些好花絮。唉,没有运气。基本上发生的事情是当我尝试在我的视图模型中循环我的结果时,从我的微风查询返回,我得到一个角度误差Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: t in vm.tracks, Duplicate key: object:00I
调用发生在我的datacontext中的一个函数中。我的querySucceeded promise回调中返回的数据似乎没有被正确绑定。
datacontext.js
...
function getTrackPartials() {
...
return EntityQuery.from(entityNames.track)
.toType(entityNames.track)
.using(manager).execute()
.then(querySucceeded, _queryFailed);
function querySucceeded(data) {
console.log(data); // <-- Log out to see what is returned
tracks = data.results;
_areTracksLoaded(true)
log('Retrieved [Track Partials] from remote data source', tracks.length, true);
return tracks;
}
}
如果我要将这些数据记录到控制台,我会得到这个(所有的$$ hashKey是相同的,id,title,description都是NULL。但我确实得到了正确的结果数,并且这不是巧合 - 如果我调整我应该接收的结果数量,它每次都正确匹配。
现在,由于我的数据有点不同 - 我使用了Edmonds example并创建了自定义JsonResultsAdapter
,因此我可以“按摩”数据。目前它非常简陋,因为我只是想让它起作用。真的让我失望的是,如果我从node
中的visitNode
函数中注销JsonResultsAdapter
参数,它就会有正确的数据.... ????
entityManagerFactory.js
(function () {
'use strict';
var serviceId = 'entityManagerFactory';
angular.module('app').factory(serviceId, ['config', emFactory]);
function emFactory(config) {
breeze.config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
breeze.NamingConvention.camelCase.setAsDefault();
var serviceName = config.remoteServiceName;
var metadataStore = new breeze.MetadataStore();
var provider = {
metadataStore: metadataStore,
newManager: newManager
};
var jsonResultsAdapter = new breeze.JsonResultsAdapter({
name: "Tracks",
extractResults: function(json) {
console.log(json.results.data); // <-- Log out to see what is returned
return json.results.data;
},
visitNode: function(node, mappingContext, nodeContext) {
console.log(node); // <-- Log out to see what is returned
return {
entityType: 'tracks',
nodeId: node.id
};
}
});
var dataService = new breeze.DataService({
serviceName: serviceName,
jsonResultsAdapter: jsonResultsAdapter
});
return provider;
function newManager() {
var mgr = new breeze.EntityManager({
dataService: dataService,
metadataStore: metadataStore
});
return mgr
}
}
})();
这是我的JsonResultsAdapter :: extractResults函数的返回值
这是我的JsonResultsAdapter :: visitNode函数中的一个节点
任何帮助将不胜感激。就像我说的,我不确定错误发生在哪里?但是,如果我不得不猜测,我会说我的EntityQuery使用我的经理和JsonResultsAdapter之间存在一些脱节,这可能是由我生成的错误元数据引起的。
** 更新 **
所以我走过微风代码,弄清楚我在哪里丢失了数据,并且能够弄清楚发生了什么,以及解决问题的方法。但是,我不确定这是否是实际处理此问题的最佳方法。
我应该提一下,我用bower来安装微风 - 通过这样做,我去了bower-breeze-angular git://github.com/eggers/bower-breeze-angular.git
包,而不是默认的微风breeze git://github.com/IdeaBlade/Breeze.git
,这是一个膨胀的示例和其他数据,我并不热衷包装到我的回购中。
在微风中,在我的JsonResultsAdapter::visitnode
回调返回后,它需要“merge”我的数据,我遇到的问题是从我的节点返回的entityKey不匹配起来。这是因为我的mappingContext
中的rawValueFn正在寻找nameOnServer
,我认为我在我的服务器中设置了元数据 - 但不知怎的,当我退出时我的数据表格已经改变了我的设置。
这是一个dp注销,如果你回顾我的元数据资源调用中的顶部,我特意将其设置为“id”。 这是如何改变为Id的?这是什么导致我的头痛!
我可以通过在我的JsonResultsAdapter
中的mappingContext上更新我的rawValueFn函数来解决这个问题,一切都会起作用 - 但这感觉就像是“黑客”。我也试过玩“NamingConvention”,但这似乎也不起作用。
这是我更新的JsonFactory,它可以使用
var jsonResultsAdapter = new breeze.JsonResultsAdapter({
name: "Tracks",
extractResults: function(json) {
return json.results.data;
},
visitNode: function(node, mappingContext, nodeContext) {
// Had to adjust this so it would lowercase and correctly match
mappingContext.rawValueFn = function(rawEntity, dp) {
name = dp.name;
name.substring(0, 1).toLowerCase() + name.substring(1);
return rawEntity[name];
}
return {
entityType: 'tracks'
};
}
});
答案 0 :(得分:3)
首先,我建议您查看"Metadata by hand"主题,该主题描述了使用Breeze Labs元数据助手定义元数据的更简单方法。这将减少很多单调乏味,使阅读和理解更加清晰。
第二次,不要在元数据中指定“jsonResultsAdapter”。在我看来,就像你将元数据固定到WebAPI适配器一样,事实上,你想要使用另一个。 不要在元数据中指定“namingConvention”,因为这将胜过您在其他地方设置的内容。鉴于您没有从服务器获取元数据,“hasServerMetadata”应该是false
,如果您根本不设置它(您不应该这样做)。
第三次,坚持客户端名称并忘记“nameOnServer”。无论如何NamingConvention
都会粉碎。
第四,如果(如图所示)客户端和服务器端属性名称是全部,则camelCase 不要更改NamingConvention
默认值!你不想要任何翻译。默认不进行翻译。
如果我对此是正确的,请不将NamingConvention
更改为camelCase! “camelCase”约定告诉Breeze“服务器是PascalCase,因此将我的客户端camel case属性名称转换为服务器上的Pascal名称”。如果我理解正确,您不希望客户端“id”成为服务器端“Id”......这将会发生什么。这就是为什么(我相信)你将“Id”视为“nameOnServer”。
第五,在JsonResultsAdapter
内,节点名称与服务器中的JSON匹配,因此是服务器端名称。保持这种方式。当NamingConvention将节点属性值转换为实体属性值时,它们会将它们转换为客户端名称。实际上,如果您错误地在节点上使用客户端名称,则会丢失数据。
当你从服务器到达时,你是否需要改变JSON中的属性名称和值?如果没有,请不要在visitNode
方法中弄乱这些名称。关于您需要做的就是确保为节点识别正确的EntityType
并将其返回到结果中。
第六次,我很确定visitNode
结果的“entityType”属性必须是实际的EntityType
,不是类型的名称< / strong>正如您在示例中所示。你不能说
return {
entityType: 'tracks',
};
你必须给它真正的类型(我很确定)
return {
entityType: trackType,
};
查看其他Breeze适配器(例如,Web API适配器)。它从EntityType
获得MetadataStore
。
第七为什么要设置“nodeId”?我不是说你做错了。但你应该知道为什么。 “nodeId”用于在同一实体在有效载荷中多次出现时帮助重建对象图。只有当某个其他节点中的“nodeRefId”指向“nodeId”值时,它才有用。此时,只有一种实体而不是关系,设置“nodeId”并不能完成任何事情。稍后它会......但只有你用一个有意义的值设置它。
我认为您正在做的是将“nodeId”设置为主键值Track
。这不是你node.id
的情况吗?如果我是对的,不要那样做。 “nodeId”是 NOT 您实体的PK。它是用循环序列化实体图的标记。
我担心你在这里有点过头了。编写dataService适配器或jsonResultsAdapter不是Breeze初学者任务。如果你要去那里,请研究现有的适配器并仔细地遵循它们。知道他们为什么做他们做的事而不是甩开它。
我希望我在这里提供了一些线索。
我怀疑它比你制作它简单得多。一些关键的想法:
确保您没有更改NamingConvention
,除非您确实需要更改客户端到服务器的属性名称拼写。
将JsonResultsAdapter中的“entityType”设置为EntityType
,而不是类型的名称。
不要重写像rawValueFn
这样的微风函数;你将打破微风,你不会知道如何或为什么。