对于整个JavaScript及其异步调用,我感到非常困惑。
这真的是一个简单的函数,或者说我是这么想的。我有一个函数,在两个不同的数据库中搜索站点id。如果在db1中找不到站点id,则必须搜索db2并将该站点保存在db1中。
我的代码如下:
var xSite='';
function getSite(siteId) {
xSite = siteId;
var predicate = Predicate.create('siteId', '==', siteId);
return EntityQuery.from(entityNames.site) //db1
.where(predicate)
.using(manager).execute()
.then(querySucceeded, _queryFailed);
function querySucceeded(data) {
if (data.results.length == 0) {
logError('Site Not Found!');
//staticDb is a separate datacontext
staticDb.getStaticSites(xSiteId).then(function(data) {
addSiteToOrg(data[0], 8);
save().then(function() {
common.$timeout(function() {
return EntityQuery.from(entityNames.site)
.where(predicate)
.using(manager).execute()
.then(querySucceeded2, _queryFailed);
}, 1250);
});
});
} else {
activeSite = data.results[0];
if (activeSite.devices.length == 0) {
getSystemsAtSite(activeSite);
}
return activeSite;
}
function querySucceeded2(data) {
activeSite = data.results[0]; //this value is correct
if (activeSite.devices.length == 0) {
getSystemsAtSite(activeSite);
}
return activeSite;
}
}
function addSiteToOrg(site, org) {
var newSite = manager.createEntity('Site', {
siteId: site.siteID,
siteName: site.name,
country: site.country
});
}
function save() {
return manager.saveChanges()
.then(saveSucceeded, saveFailed);
function saveSucceeded(result) {
logSuccess('Saved data', result, true);
}
function saveFailed(error) {
var msg = config.appErrorPrefix + 'Save failed: ' +
breeze.saveErrorMessageService.getErrorMessage(error);
error.message = msg;
logError(msg, error);
throw error;
}
}实际发生的是一些混乱的东西:(与上面的数字相同)
在保存完成之后,我不知道它会去哪里,因为它没有去链式函数。
我不知道如何保存这个网站之前,我必须找到它,然后返回到UI。我试过用q,延迟,超时之类的.什么都行!但我似乎无法按正确的行动顺序行事。
为什么会出故障?保存后不应该执行".then()“吗?
编辑1:从querySucceed2返回的内容不存在任何地方。在执行addSiteToOrg()或save()之前,已经返回未定义的函数。
发布于 2014-10-18 23:29:56
这是个很有趣的问题,我不得不尝试一下.或者是一些接近的东西。
我为它编写了一个mocha/chai测试,它使用了轻松的DocCode示例Web,它有两个碰巧访问同一个数据库的控制器(Northwind)。
我做了两个简化的假设:
siteID是“站点”类型的关键属性(就像CustomerID是"Customer“类型的键一样)。下面是我写的测试:
it("your example", function(done){
var id = alfredsID; // testFns.wellKnownData.emptyGuid;
var ds1 = new breeze.DataService({serviceName: 'http://localhost:58066/breeze/Northwind'});
var ds2 = new breeze.DataService({serviceName: 'http://localhost:58066/breeze/NorthwindDto'});
em.fetchEntityByKey('Customer', id, true /* search cache first; then go to server */)
.then(firstQuerySuccess)
.then(confirmResult)
.then(done, done); // test artifact; ignore in your code
function firstQuerySuccess(data){
var entity = data.entity;
if (entity){ return entity; } // got it
// not found; query again in second data source
switchToDataSource2(em);
var key = data.entityKey; // same key as before
var promise = em.fetchEntityByKey(key, false /* only go to server #2*/)
.then(secondQuerySuccess);
switchToDataSource1(em); // immediately, before async call returns
return promise; // from the second query
}
function secondQuerySuccess(data){
var entity = data.entity;
if (!entity){ return entity; } // can't find it in the 2nd source either; give up
// although it was retrieved from DS2, it's actually new in DS1
entity.entityAspect.setAdded();
return em.saveChanges([entity])
.then(function saveSucceeded (){ return entity; }, // we've got it; no need to refetch it.
function saveFailed (error) {
if (/duplicate/.test(error.message)) {
// it's already in ds1; race condition?; assume so and reverse the add
entity.entityAspect.setUnchanged();
return entity;
} else {
// something bad happened; remove from cache and forward the error
entity.entityAspect.setDetached();
return breeze.Q.reject(error);
}
});
}
function switchToDataSource1(em){
em.setProperties({dataService: ds1});
}
function switchToDataSource2(em){
em.setProperties({dataService: ds2});
em.metadataStore.addDataService(ds2, true /*overwrite if found */);
}
// You would add your own success function to do what you want with the entity
// Here we apply chai.js expectations to confirm that the entity is what we expected.
function confirmResult(entity){
if (entity){
var key = entity.entityAspect.getKey();
expect(entity.entityType.shortName).to.equal('Customer', 'EntityType is '+entity.entityType.name);
expect(entity.entityAspect.entityState).to.equal(breeze.EntityState.Unchanged,
'EntityState is '+entity.entityAspect.entityState.name);
expect(key.values[0]).to.equal(id, 'key is '+JSON.stringify(key));
} else {
expect(false).to.equal(true,
'Did not find entity with ID='+id+ ' in either data source');
}
}
})观察
这“工作”的意义上说,代码做的正是我想要它做的.我希望这正是你想要做的。在我看来,这确实是按照你描述的顺序进行的。
我被我没有两个数据库的事实所阻碍。本例中的两个数据源实际上引用相同的物理数据库。因此,我没有客户在ds2而不是ds1的情况。这意味着我所寻找的id的实体总是要么在ds1中找到,要么在其中任何一个中找不到。
我可以通过注释掉ds1中的快速返回来模拟无法在firstQuerySuccess中找到它
// if (entity){ return entity; } // got it注意,对于第二个查询,我必须暂时将管理器的DataService更改为DS2 (switchToDataSource2)。我只做了足够长的时间来评估查询并在服务器上启动它。我立即将它切换回DS1 (在switchToDataSource1中),以便以后使用这个em的查询使用DS1。我只需要向服务器发出查询所需的时间长度的DS2。
还请注意,我在switchToDataSource2中确保em中的MetadataStore与DS1和DS2相关联。我正在利用我前面提到的简化假设#2。
现在,实体在第二个数据源中找到了。
我必须把它的状态设置为“添加”。这很关键!我们以不变的状态从ds2检索该实体。但是它并不存在于ds1中,所以我们必须将它的状态更改为“添加”。
现在我可以把它保存到DS1了。
我不需要在保存后重新获取实体。我已经把它藏起来了。因此,如果保存成功,我就可以返回它。
最后的.then(done, done)是一个测试工件,不会成为代码的一部分。您的代码实际上会在confirmResult中执行任何适当的操作。
实际上,保存总是失败的,因为实体已经存在于ds1 (记住,ds1和ds2实际上映射到同一个数据库)。这对你来说不是问题。
或者它也可能发生在你身上!通常情况下,其他用户可能同时查找相同的siteID,并在此之前成功地保存到ds1。你会输掉比赛,你会得到与我相同的“重复”错误。我向您展示了如何在saveFailed回调中处理这个问题。
最后一点:请注意,每个承诺回调都会返回一个承诺或一个值。你必须这样做,以保持回调的流动。否则,这条链就会被打破,应用程序似乎会漂向太空。
只有最后一个confirmResult回调忽略了返回一个值;它不应该返回一个值,否则摩卡测试就会崩溃(不要让我解释)。如果实体辜负了期望,confirmResult将抛出异常..。这也很好。
享受吧!
发布于 2014-10-17 23:20:31
我将使用简化的函数名,因为我不知道什么EntityQuery等等.准确地说
function getSite(sideId) {
return search(db1, siteId)
.then(function(data) {
if (data.length > 0) return data;
var fallbackSearchPromise =
search(db2, siteId)
.then(function(data) {
if (data.length === 0) return null;
return save(db1, data);
})
.then(function(saveResult) {
if (saveResult !== null) return null;
return search(db1, siteId);
});
return fallbackSearchPromise;
});
}https://stackoverflow.com/questions/26433462
复制相似问题