2

长期 .NET 开发人员刚刚构建了我的第一个 Web 应用程序。我正在尝试使用我认为我在架构上理解的 Durandal、Breeze 和 Knockout。然而,这并没有改变这样一个事实,即我觉得我只是带着一些 jQuery 的基本概念来到了异国他乡。

我在使用 Q 的 Promise 概念进行异步编程时遇到了问题。通常,在 KO 视图模型中会有一个用于 Durandal 的“激活”处理程序,其功能如下:

var activate = function() {
    return ebodatacontext.getOrganizations(organizations);
};

其中调用 Breeze 数据上下文以通过 api 从实体获取数据,并且“组织”是 ko.observableArray。在我的应用程序中,这工作正常。

但是,在我的情况下,我的视图有两个实体列表,因此我需要对我与 Q 放在一起的 datacontext 进行两次调用,如下所示:

var activate = function() {
    var promise =
        Q.all([
            ebodatacontext.getOrganizations(organizations),
            ebodatacontext.getUserRoles(userRoles)
        ]);
    return promise;
};

据我所知,这些 datacontext 调用中的任何一个都可以自行工作并将 ok 绑定到视图。但是当他们像这样智商时,似乎只有第一个有效。我担心我在这里遗漏了一些基本的东西。

我可以在网络流量中看到两个 api 调用都是针对两组实体进行的。并通过网络返回良好的结果。

但是,似乎第二次调用的 ko.observable (userRoles) 并没有以任何数据结束。如果我交换它们的顺序,在 Q 数组中,第一个有效。在我看来,我在这里忽略了一些东西,并且绑定发生得太快了。

如果我在这里使用的 Q 是正确的,我会假设我在其他地方还有更多的调试要做。提前致谢。

这是使用 Breeze 的 ebodatacontext:

define([
    'durandal/system',
    'services/ebomodel',
    'config',
    'services/logger'],
    function (system, ebomodel, config, logger) {

        var EntityQuery = breeze.EntityQuery;
        var manager = configureBreezeManager();
        var orderBy = ebomodel.orderBy;
        var entityNames = ebomodel.entityNames;

        var getOrganizations = function(organizationsObservable, forceRemote) {
            if (!forceRemote) {
                var p = getLocal('Organizations', orderBy.Name);
                if (p.length > 0) {
                    organizationsObservable(p);
                    return Q.resolve();
                }
            }

            var query = EntityQuery.from('Organizations')
                //.orderBy(orderBy.Name)
                ;

            return manager.executeQuery(query)
                .then(querySucceeded)
                .fail(queryFailed);

            function querySucceeded(data) {
                if (organizationsObservable) {
                    organizationsObservable(data);
                }
                log('Retrieved [Organizations] from remote data source',
                    data, true);
            }
        };

        var getUserRoles = function(rolesObservable, forceRemote) {
            if (!forceRemote) {
                var p = getLocal('UserRoles', orderBy.Name);
                if (p.length > 0) {
                    rolesObservable(p);
                    return Q.resolve();
                }
            }

            var query = EntityQuery.from('UserRoles')
              //  .orderBy(orderBy.Name)
                ;

            return manager.executeQuery(query)
                .then(querySucceeded)
                .fail(queryFailed);

            function querySucceeded(data) {
                if (rolesObservable) {
                    rolesObservable(data);
                }
                log('Retrieved [UserRoles] from remote data source',
                    data, true);
            }
        };

        var cancelChanges = function() {
            manager.rejectChanges();
            log('Canceled changes', null, true);
        };

        var saveChanges = function() {
            return manager.saveChanges()
                .then(saveSucceeded)
                .fail(saveFailed);

            function saveSucceeded(saveResult) {
                log('Saved data successfully', saveResult, true);
            }

            function saveFailed(error) {
                var msg = 'Save failed: ' + error.message;
                logError(msg, error);
                error.message = msg;
                throw error;
            }
        };

        var primeData = function () {
         };

        var createOrganization = function() {
            return manager.createEntity(entityNames.organization);
        };

        var createUserRole = function() {
            return manager.createEntity(entityNames.role);
        };

        var hasChanges = ko.observable(false);

        manager.hasChangesChanged.subscribe(function(eventArgs) {
            hasChanges(eventArgs.hasChanges);
        });

        var ebodatacontext = {
            createOrganization: createOrganization,
            createUserRole: createUserRole,
            getOrganizations: getOrganizations,
            getUserRoles: getUserRoles,
            hasChanges: hasChanges,
            primeData: primeData,
            cancelChanges: cancelChanges,
            saveChanges: saveChanges
        };

        return ebodatacontext;

        //#region Internal methods        

        function getLocal(resource, ordering, includeNullos) {
            var query = EntityQuery.from(resource)
 //               .orderBy(ordering)
                ;
            //if (!includeNullos) {
            //    query = query.where('id', '!=', 0);
            //}
            return manager.executeQueryLocally(query);
        }

        function queryFailed(error) {
            var msg = 'Error retreiving data. ' + error.message;
            logger.logError(msg, error, system.getModuleId(ebodatacontext), true);
            throw error;
        }

        function configureBreezeManager() {
            breeze.NamingConvention.camelCase.setAsDefault();
            var mgr = new breeze.EntityManager(config.eboRemoteServiceName);
            ebomodel.configureMetadataStore(mgr.metadataStore);
            return mgr;
        }

        function log(msg, data, showToast) {
            logger.log(msg, data, system.getModuleId(ebodatacontext), showToast);
        }
        //#endregion
});
4

1 回答 1

1

我正在回答我自己的问题,因为我认为问题是由于 Q 和 promises 造成的。看来我的工作正常。

通过意识到在 Breeze 数据上下文中,我需要用 data.result 而不是数据初始化传入的 ko.observableArray,我的所有问题都得到了解决。

我的破代码:

    var getOrganizations = function (organizationsObservable) {

        var query = EntityQuery.from('Organizations');

        return manager.executeQuery(query)
            .then(querySucceeded)
            .fail(queryFailed);

        function querySucceeded(data) {
            if (organizationsObservable) {
                organizationsObservable(data);
            }
            log('Retrieved [Organizations] from remote data source',
                data, true);
        }
    };

我的有效代码:

    var getOrganizations = function (organizationsObservable) {

        var query = EntityQuery.from('Organizations');

        return manager.executeQuery(query)
            .then(querySucceeded)
            .fail(queryFailed);

        function querySucceeded(data) {
            if (organizationsObservable) {
                organizationsObservable(data.results);
            }
            log('Retrieved [Organizations] from remote data source',
                data, true);
        }
    };

如果您像我一样对此不熟悉,那么线索是当您观察返回的 ko.observableArray 的内容时,它不应该是 XHR 类型的单个对象(呃,呃)。从 API 调用返回到控制器的 XHR 在“结果”字段中具有实际日期。

感谢大家容忍新手尝试将所有最新技术用于 SPA 客户端应用程序。

好消息是,尽管我对一些基础知识仍然一无所知,但我正在努力拥有一个具有完整数据生命周期和导航的富客户端,它看起来像一个专业站点(感谢 bootstrap)。

我想对 John Papa 的 Pluralsight 课程和关于 SPA 应用程序的博客文章以及他的 Hot Towel 模板表示赞赏。

http://www.johnpapa.net/hottowel/

于 2013-05-21T22:44:35.087 回答