【问题标题】:Breezejs EntityManager MetadataStore and fetchEntityByKeyBreezejs EntityManager MetadataStore 和 fetchEntityByKey
【发布时间】:2013-02-12 01:21:03
【问题描述】:

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

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

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

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

问题是当我调用 manager.fetchEntityByKey("Todos", id) 时,EntityManager 还没有来自服务器的元数据,所以它抛出异常“无法通过名称找到 'Type': 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);
    }
};

【问题讨论】:

    标签: breeze durandal


    【解决方案1】:

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

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

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

    【讨论】:

    • 好建议,所以我将创建带有工厂的实体管理器,在它们之间共享全局元数据。顺便说一句,是否有机会改进微风以添加此功能,例如 metadatastore 的全局实例?或者然后强制 entitymanager 查询元数据,即使我只想 fetchEntityByKey,而不对服务运行完整查询?
    • 不确定你的意思。我并不热衷于 Breeze 定义的默认 MetadataStore,但您可以轻松地为自己创建。您可以告诉 MetadataStore 获取元数据(当然这是异步的),而不是查询(我在回答中提到了这一点)。你也可以看看EntityManager.createEmptyCopy。你可以在你的主 EM 上调用它来创建完全配置的新的空 EM;您的工厂方法的其余部分将从 master 仅导入您想要在副本中的那些实体(例如,参考列表)。
    【解决方案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;
    });
    

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

    【讨论】:

    • 我也有 Silverlight/Caliburn.Micro 和 WCF Ria 服务的背景。实际上,如果您使用 MVC 中的 Bundles,您可以在捆绑的脚本中包含微风.min.js,并且您不需要调用 require('path/to/breeze')。见我的durandal video。我的问题是我想要元数据而不先进行查询。谢谢!
    • 我想这对我有用,因为我使用查询来获取单个实体。 var query = blink.EntityQuery.from("AthleteDetails").where("Id", "==", id);
    • 是的,因为如果您使用 EntityQuery,您正在运行一个查询,如果管理器之前没有获取过元数据,您将运行一个查询...查询的结果将是一个实体数组,所以您需要通过像 result.entities[0] 这样的零索引来访问它。 fetchEntityByKey() 的情况并非总是返回单个实体或 null,如果需要,可以选择从缓存中返回实体,但它不会为管理器获取元数据,如果我不手动获取,则会抛出异常,就像我做的那样在问题中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多