5

我有一个 SPA 应用程序(durandaljs),并且我有一个特定的路线,我在其中映射我想要获取的实体的“id”。

模板是“/#/todoDetail/:id”。

例如,“/#/todoDetail/232”或“/#/todoDetail/19”。

在 viewmodel 的激活功能上,我得到了路线信息,所以我可以获取 id。然后我创建一个新的微风 EntityManager 实例来获取具有给定 id 的实体。

问题是当我调用 manager.fetchEntityByKey("Todos", id) 时,EntityManager 还没有来自服务器的元数据,所以它抛出异常“无法通过名称找到‘类型’:Todos”。

仅当我在调用 fetchEntityByKey 之前首先对存储 (manager.executeQuery) 执行查询时,它才有效。

这是预期的行为还是错误?有没有办法在 EntityManager 的实例化过程中自动修改元数据?

注意:我认为在我的情况下很难使用共享的 EntityManager,因为我希望允许用户直接在浏览器上键入路由。

编辑:作为临时解决方法,我正在这样做:

BreezeService.prototype.get = function (id, callback) {
    var self = this;

    function queryFailed(error) {
        app.showMessage(error.message);
        callback({});
    }

    /* first checking if metadatastore was already loaded */

    if (self.manager.metadataStore.isEmpty()) {
        return self.manager.fetchMetadata()
        .then(function (rawMetadata) {
            return executeQuery();
        }).fail(queryFailed);
    } else {
        return executeQuery();
    }

    /* Now I can fetch */
    function executeQuery() {
        return self.manager.fetchEntityByKey(self.entityType, id, true)
                        .then(callback)
                        .fail(queryFailed);
    }
};
4

2 回答 2

7

你已经了解了fetchMetadata. 这很重要。如果您的应用程序可以在不发出查询的情况下开始,您必须使用fetchMetadata并等待它返回,然后才能直接对缓存执行任何操作(例如,在回退到数据库查询之前通过缓存中的键检查实体) .

但我感觉到发生了其他事情,因为你提到了多个经理。默认情况下,新经理不知道任何其他经理的元数据。但是您知道您可以在管理人员之间共享一个 metadataStore吗?你可以。

我经常做的(你会在 DocCode 示例的元数据测试中看到它)是为应用程序获取一个 metadataStore,编写一个 EntityManager 工厂函数,该函数使用该 metadataStore 创建新的管理器,然后每当我使用工厂我在做新的经理……就像你在启动 ViewModel 以查看 TodoDetail 时所做的那样。

于 2013-02-11T06:49:42.427 回答
2

来自 Silverlight 背景,我使用了很多 WCF RIA 服务和 Caliburn Micro,我使用这种方法将 Breeze 与 Durandal 集成。

我在应用程序的 App 文件夹中创建了一个名为 services 的子文件夹。在那个文件夹中,我创建了一个名为 datacontext.js 的 javascript 文件。这是我的数据上下文的一个子集:

define(function (require) {

    var breeze = require('lib/breeze'); // path to breeze
    var app = require('durandal/app');  // path to durandal

    breeze.NamingConvention.camelCase.setAsDefault();

    // service name is route to the Web API controller
    var serviceName = 'api/TeamData',

    // manager is the service gateway and cache holder
    manager = new breeze.EntityManager(serviceName),

    store = manager.metadataStore;

    function queryFailed(error) {
        app.showMessage("Query failed: " + error.message);
    }

    // constructor overrides here

    // included one example query here
    return datacontext = {
        getSponsors: function (queryCompleted) {
            var query = breeze.EntityQuery.from("Sponsors");
            return manager
                .executeQuery(query)
                .then(queryCompleted)
                .fail(queryFailed)
        }
    };
}

然后在您的 durandal 视图模型中,您可以只需要服务/数据上下文。例如,这是我的应用程序中示例视图模型的一部分:

define(function (require) {

    var datacontext = require('services/datacontext');

    var ctor = function () {
        this.displayName = 'Sponsors',
        this.sponsors = ko.observable(false)
    };

    ctor.prototype.activate = function () {
        var that = this;
        return datacontext.getSponsors(function (data) { that.sponsors(data.results) });
    }

    return ctor;
});

这将使您不必担心在每个视图模型中初始化元数据存储,因为它都在一个地方完成。

于 2013-02-11T17:20:19.687 回答