我可以在 breeze 实体实现管道的哪个位置设置非实体 object 的原型?
where in the breeze entity materialization pipeline can i set a non entity object's prototype?
这个问题基本上是我几周前问的同一个问题... how to tap into mappingcontext.processAnonType...我把这个问题标记为错误回答,从那以后就没能得到任何跟进。
基本上我想弄清楚的是 breeze 管道中的一个位置,当 object 从服务器具体化时,我可以设置一个非实体 object 的原型结果...当 breeze 处理来自非实体服务器的结果时,它最终调用助手 MappingContext
class 下面的方法...此方法如下:
function processAnonType(mc, node) {
// node is guaranteed to be an object by this point, i.e. not a scalar
var keyFn = mc.metadataStore.namingConvention.serverPropertyNameToClient;
var result = {};
__objectForEach(node, function (key, value) {
var newKey = keyFn(key);
var nodeContext = { nodeType: "anonProp", propertyName: newKey };
visitNode(value, mc, nodeContext, result, newKey);
});
return result;
}
高于 "results" 的值是客户端最终从 breeze 收到的...这是一个完美的地方,我可以做我想做的事,因为我可以访问最终的 object ("results") 和 node.$type
属性...我基本上想按顺序解析 node.$type
属性找出非实体的原型 object...不幸的是它没有出现 processAnonType
是管道内的拦截点...在我问的上一个问题中,我被指示查看一个自定义的 jsonresultsadapter...我做到了,但我不认为它会起作用,因为 jsonresultsadapter 似乎从未处于改变 "results" 值的位置(最后的 object returned)...所以即使我实现了自定义 jsonresulsadapter
和 return 新节点,上面 "results" 的值仍然相同...任何人都可以请给我线索?谢谢
编辑#1:我已经尝试过使用自定义 jsonresultsadapter……但这对我特别想做的事情不起作用,除非我使用的是非常旧版本的 breeze(不太可能)或者我遗漏了一些非常明显的东西(更有可能)......在下面我提供了两个 breeze 代码片段,希望可以帮助我解释我的结论......第一个片段是映射上下文的“visitandmerge”方法......在该方法的底部,您会看到对“jra.visitnode”的调用……太棒了……它调用了我的自定义 jra 实现,结果中 return 是一个“节点”属性,这样以下行将使用该节点而不是原始节点……到目前为止一切顺利……然后在最后您会看到对“processmeta”进行了调用,该调用传入了我的自定义节点……好的……但是如果您看在我的例子中,“processmeta”代码最后一个“else”块最终被调用并调用“processanontype”……这就是问题所在……此时我的自定义节点被丢弃 f或 creating/instantiating 最终 object return 发送给客户的目的……我知道我的自定义节点将用于为最终 object 创建属性,但这不是我的意思之后...相反,我需要通过设置其原型来自己操作最终的 object...正如我之前提到的,如果您查看“processanontype”方法,它会创建一个新的 object(var result = { };) object 被 return 发送给客户端,而不是我的自定义节点,这与文档所说的一致......请查看我在之前 post 中留下的所有评论...你明白我的问题是什么吗?我可能在这里遗漏了一些非常明显的东西……你能告诉我吗?再次感谢
proto.visitAndMerge = function (nodes, nodeContext) {
var query = this.query;
var jra = this.jsonResultsAdapter;
nodeContext = nodeContext || {};
var that = this;
return __map(nodes, function (node) {
if (query == null && node.entityAspect) {
// don't bother merging a result from a save that was not returned from the server.
if (node.entityAspect.entityState.isDeleted()) {
that.entityManager.detachEntity(node);
} else {
node.entityAspect.acceptChanges();
}
return node;
}
var meta = jra.visitNode(node, that, nodeContext) || {};
node = meta.node || node;
if (query && nodeContext.nodeType === "root" && !meta.entityType) {
meta.entityType = query._getToEntityType && query._getToEntityType(that.metadataStore);
}
return processMeta(that, node, meta);
});
};
function processMeta(mc, node, meta, assignFn) {
// == is deliberate here instead of ===
if (meta.ignore || node == null) {
return null;
} else if (meta.nodeRefId) {
var refValue = resolveEntityRef(mc, meta.nodeRefId);
if (typeof refValue === "function" && assignFn != null) {
mc.deferredFns.push(function () {
assignFn(refValue);
});
return undefined; // deferred and will be set later;
}
return refValue;
} else if (meta.entityType) {
var entityType = meta.entityType;
if (mc.mergeOptions.noTracking) {
node = processNoMerge(mc, entityType, node);
if (entityType.noTrackingFn) {
node = entityType.noTrackingFn(node, entityType);
}
if (meta.nodeId) {
mc.refMap[meta.nodeId] = node;
}
return node;
} else {
if (entityType.isComplexType) {
// because we still need to do serverName to client name processing
return processNoMerge(mc, entityType, node);
} else {
return mergeEntity(mc, node, meta);
}
}
} else {
if (typeof node === 'object' && !__isDate(node)) {
node = processAnonType(mc, node);
}
// updating the refMap for entities is handled by updateEntityRef for entities.
if (meta.nodeId) {
mc.refMap[meta.nodeId] = node;
}
return node;
}
}
您不需要修改 processAnonType 方法。
jsonResultsAdapter 中 visitNode 方法的参数包含您说需要的有关被访问节点的所有信息。 (请参阅此 post 底部的 link)。 visitNode 的结果是一个具有以下属性的对象:
entityType: you should return null for an anonymous type
nodeId and nodeRefId: ( probably not needed for an anonymous objects unless you plan to return multiple refs to the same object)
ignore: boolean - (if you want to completely ignore the node).
node: This is where you can take the incoming node ( the first parameter in the visitNode parameter list) and modify it, or return a completely new node object that represents your anonType instance. This object will be returned to the client unchanged, so you can create an new instance of your object with whatever prototype you want. If you don't set this property then the original incoming node will be used.
passThru: (avail in breeze versions > v 1.5.4) boolean - you should return true to return the node (above) intact without ANY further processing.
因此您的 visitNode 将如下所示:
visitNode: function(node, mappingContext, nodeContext) {
// 'isAnonType' is your method that determines if this is an anon type
var isAnon = isAnonType(node.$type);
if (isAnonType) {
// 'createCustomAnonNode' is your method where you create a copy of the node with whatever prototype you want.
// prototype you want.
var newNode = createCustomAnonNode(node);
return {
return { passThru: true, node: newNode };
}
} else {
// assuming that you kept track of the default JsonResultsAdapter;
return defaultAdapter.visitNode(node, mappingContext, nodeContext);
}
}
详情请见:
http://www.getbreezenow.com/documentation/jsonresultsadapters
这个问题基本上是我几周前问的同一个问题... how to tap into mappingcontext.processAnonType...我把这个问题标记为错误回答,从那以后就没能得到任何跟进。
基本上我想弄清楚的是 breeze 管道中的一个位置,当 object 从服务器具体化时,我可以设置一个非实体 object 的原型结果...当 breeze 处理来自非实体服务器的结果时,它最终调用助手 MappingContext
class 下面的方法...此方法如下:
function processAnonType(mc, node) {
// node is guaranteed to be an object by this point, i.e. not a scalar
var keyFn = mc.metadataStore.namingConvention.serverPropertyNameToClient;
var result = {};
__objectForEach(node, function (key, value) {
var newKey = keyFn(key);
var nodeContext = { nodeType: "anonProp", propertyName: newKey };
visitNode(value, mc, nodeContext, result, newKey);
});
return result;
}
高于 "results" 的值是客户端最终从 breeze 收到的...这是一个完美的地方,我可以做我想做的事,因为我可以访问最终的 object ("results") 和 node.$type
属性...我基本上想按顺序解析 node.$type
属性找出非实体的原型 object...不幸的是它没有出现 processAnonType
是管道内的拦截点...在我问的上一个问题中,我被指示查看一个自定义的 jsonresultsadapter...我做到了,但我不认为它会起作用,因为 jsonresultsadapter 似乎从未处于改变 "results" 值的位置(最后的 object returned)...所以即使我实现了自定义 jsonresulsadapter
和 return 新节点,上面 "results" 的值仍然相同...任何人都可以请给我线索?谢谢
编辑#1:我已经尝试过使用自定义 jsonresultsadapter……但这对我特别想做的事情不起作用,除非我使用的是非常旧版本的 breeze(不太可能)或者我遗漏了一些非常明显的东西(更有可能)......在下面我提供了两个 breeze 代码片段,希望可以帮助我解释我的结论......第一个片段是映射上下文的“visitandmerge”方法......在该方法的底部,您会看到对“jra.visitnode”的调用……太棒了……它调用了我的自定义 jra 实现,结果中 return 是一个“节点”属性,这样以下行将使用该节点而不是原始节点……到目前为止一切顺利……然后在最后您会看到对“processmeta”进行了调用,该调用传入了我的自定义节点……好的……但是如果您看在我的例子中,“processmeta”代码最后一个“else”块最终被调用并调用“processanontype”……这就是问题所在……此时我的自定义节点被丢弃 f或 creating/instantiating 最终 object return 发送给客户的目的……我知道我的自定义节点将用于为最终 object 创建属性,但这不是我的意思之后...相反,我需要通过设置其原型来自己操作最终的 object...正如我之前提到的,如果您查看“processanontype”方法,它会创建一个新的 object(var result = { };) object 被 return 发送给客户端,而不是我的自定义节点,这与文档所说的一致......请查看我在之前 post 中留下的所有评论...你明白我的问题是什么吗?我可能在这里遗漏了一些非常明显的东西……你能告诉我吗?再次感谢
proto.visitAndMerge = function (nodes, nodeContext) {
var query = this.query;
var jra = this.jsonResultsAdapter;
nodeContext = nodeContext || {};
var that = this;
return __map(nodes, function (node) {
if (query == null && node.entityAspect) {
// don't bother merging a result from a save that was not returned from the server.
if (node.entityAspect.entityState.isDeleted()) {
that.entityManager.detachEntity(node);
} else {
node.entityAspect.acceptChanges();
}
return node;
}
var meta = jra.visitNode(node, that, nodeContext) || {};
node = meta.node || node;
if (query && nodeContext.nodeType === "root" && !meta.entityType) {
meta.entityType = query._getToEntityType && query._getToEntityType(that.metadataStore);
}
return processMeta(that, node, meta);
});
};
function processMeta(mc, node, meta, assignFn) {
// == is deliberate here instead of ===
if (meta.ignore || node == null) {
return null;
} else if (meta.nodeRefId) {
var refValue = resolveEntityRef(mc, meta.nodeRefId);
if (typeof refValue === "function" && assignFn != null) {
mc.deferredFns.push(function () {
assignFn(refValue);
});
return undefined; // deferred and will be set later;
}
return refValue;
} else if (meta.entityType) {
var entityType = meta.entityType;
if (mc.mergeOptions.noTracking) {
node = processNoMerge(mc, entityType, node);
if (entityType.noTrackingFn) {
node = entityType.noTrackingFn(node, entityType);
}
if (meta.nodeId) {
mc.refMap[meta.nodeId] = node;
}
return node;
} else {
if (entityType.isComplexType) {
// because we still need to do serverName to client name processing
return processNoMerge(mc, entityType, node);
} else {
return mergeEntity(mc, node, meta);
}
}
} else {
if (typeof node === 'object' && !__isDate(node)) {
node = processAnonType(mc, node);
}
// updating the refMap for entities is handled by updateEntityRef for entities.
if (meta.nodeId) {
mc.refMap[meta.nodeId] = node;
}
return node;
}
}
您不需要修改 processAnonType 方法。
jsonResultsAdapter 中 visitNode 方法的参数包含您说需要的有关被访问节点的所有信息。 (请参阅此 post 底部的 link)。 visitNode 的结果是一个具有以下属性的对象:
entityType: you should return null for an anonymous type
nodeId and nodeRefId: ( probably not needed for an anonymous objects unless you plan to return multiple refs to the same object)
ignore: boolean - (if you want to completely ignore the node).
node: This is where you can take the incoming node ( the first parameter in the visitNode parameter list) and modify it, or return a completely new node object that represents your anonType instance. This object will be returned to the client unchanged, so you can create an new instance of your object with whatever prototype you want. If you don't set this property then the original incoming node will be used.
passThru: (avail in breeze versions > v 1.5.4) boolean - you should return true to return the node (above) intact without ANY further processing.
因此您的 visitNode 将如下所示:
visitNode: function(node, mappingContext, nodeContext) {
// 'isAnonType' is your method that determines if this is an anon type
var isAnon = isAnonType(node.$type);
if (isAnonType) {
// 'createCustomAnonNode' is your method where you create a copy of the node with whatever prototype you want.
// prototype you want.
var newNode = createCustomAnonNode(node);
return {
return { passThru: true, node: newNode };
}
} else {
// assuming that you kept track of the default JsonResultsAdapter;
return defaultAdapter.visitNode(node, mappingContext, nodeContext);
}
}
详情请见:
http://www.getbreezenow.com/documentation/jsonresultsadapters