首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >具有多个数据库且保存顺序不正确的AngularJS异步调用

具有多个数据库且保存顺序不正确的AngularJS异步调用
EN

Stack Overflow用户
提问于 2014-10-17 21:08:42
回答 2查看 418关注 0票数 0

对于整个JavaScript及其异步调用,我感到非常困惑。

这真的是一个简单的函数,或者说我是这么想的。我有一个函数,在两个不同的数据库中搜索站点id。如果在db1中找不到站点id,则必须搜索db2并将该站点保存在db1中。

  1. 传入一个siteId
  2. 在siteId中搜索db1
  3. 无法在siteId中找到db1,请搜索db2
  4. 从db2获取站点
  5. 将站点保存在db1中
  6. 再次搜索db1以查找该站点
  7. 将要显示的站点返回给UI

我的代码如下:

代码语言:javascript
复制
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;
          }
     }

实际发生的是一些混乱的东西:(与上面的数字相同)

    1. 传入一个siteId
    2. 在siteId中搜索db1
    3. 无法在siteId中找到db1,请搜索db2 ->超时值-> 7。
    4. 从db2获取站点
    5. 再次搜索db1以查找该站点
    6. 将站点保存在db1中

在保存完成之后,我不知道它会去哪里,因为它没有去链式函数。

我不知道如何保存这个网站之前,我必须找到它,然后返回到UI。我试过用q,延迟,超时之类的.什么都行!但我似乎无法按正确的行动顺序行事。

为什么会出故障?保存后不应该执行".then()“吗?

编辑1:从querySucceed2返回的内容不存在任何地方。在执行addSiteToOrg()或save()之前,已经返回未定义的函数。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-18 23:29:56

这是个很有趣的问题,我不得不尝试一下.或者是一些接近的东西。

我为它编写了一个mocha/chai测试,它使用了轻松的DocCode示例Web,它有两个碰巧访问同一个数据库的控制器(Northwind)。

我做了两个简化的假设:

  1. siteID是“站点”类型的关键属性(就像CustomerID是"Customer“类型的键一样)。
  2. 元数据对于两个数据源中的实体(此处为"Customer",对您来说是"Site")是相同的。我想象db2具有与db1相同的结构。

下面是我写的测试:

代码语言:javascript
复制
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中找到它

代码语言:javascript
复制
// 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将抛出异常..。这也很好。

享受吧!

票数 1
EN

Stack Overflow用户

发布于 2014-10-17 23:20:31

我将使用简化的函数名,因为我不知道什么EntityQuery等等.准确地说

代码语言:javascript
复制
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;

    });
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26433462

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档