编辑或删除BreezeJS EntityManager一旦实例参考丢失

时间:2014-07-24 12:39:43

标签: javascript angularjs breeze

我正在使用 BreezeJS AngularJS 构建具有SPA结构的CRM应用程序,并且我正在利用动态生成的选项卡式环境来以模块显示我在此处引用的内容。当用户单击侧面菜单项时,将创建一个新选项卡,并将HTML模板( aka模块)加载到新的内容区域中。虽然某些模块类型一次只能打开一次(帐户网格),但其他模块类型(例如帐户编辑器模块)可以多次打开。这样,用户可以在一天中的任何给定时间修改多个帐户,但始终是从单个帐户网格实例执行此操作。

到目前为止,我有一个帐户编辑器模块的工作系统,我创建了一个具有适当配置参数(服务名称,保存选项等)的主Breeze EntityManager,然后复制它创建新帐户编辑器的时间,使用 masterManager.createEmptyCopy() (根据http://www.breezejs.com/documentation/multiple-managers#CreateMultipleManagers中列出的代码):

var serviceName = "/breeze/accounts";

var ds = new breeze.DataService({
    serviceName: serviceName,
    hasServerMetadata: true
});

var masterManager = new breeze.EntityManager({
               dataService: ds,
               saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: false })
           });

function createManagerCopy() {
    // same configuration as master; no entities in cache.
    var sandboxManager = masterManager.createEmptyCopy();
    return sandboxManager;
}

然后,我通过传入复制的EntityQuery和实体EntityManager来调用Id (key),以便获取相应的帐户并填充每个打开的编辑器,显然具有以下所有优点:微风。

function queryAccountByKey(mgr, key) {
    var keyPredicate = breeze.Predicate.create('id', 'eq', key);
    var query = new breeze.EntityQuery('AccountsBase')
                          .expand('ContactsBase')
                          .where(keyPredicate);

    var promise = mgr.executeQuery(query)
                     .catch(queryFailed);

    return promise;

    function queryFailed(error) {
        console.log('Query Account by Id Failed', error);
        return $q.reject(error); // so downstream promise users know it failed
    }
}

与其他公开编辑及其各自的实体经理似乎没有任何冲突,我在模块中维护复制的 EntityManager Angular scope。编辑和保存这种方式,是......轻而易举! :P (对不起)

我遇到的问题是当我切换到另一个Angular route时,例如登录屏幕,然后回到主屏幕。由于每个选项卡式模块的复杂性,我在路由发生之前打开的任何帐户编辑器模块必须从存储的设置重新加载(即使布局存储在缓存中)。但是,有两个Breeze实体经理处理该帐户。 效果是,保存单个帐户编辑器的更改现在提交两次(或者无论多少次您离开并从主页布局返回)。

我想弄清楚的是,一旦我导航回家庭版布局,我就会从客户端访问特定的 EntityManager 实例原始实例引用(在我的情况下,在范围内)丢失。换句话说,我可以查询重用或删除实例的EntityManager 集合吗?如果我可以按名称或其他ID获取管理器实例,我可以简单地将其重新分配给我的范围,而无需删除并重新创建它。

如果我确实需要移除EntityManager,我无法在任何地方找到任何描述类似destroy()方法的内容...只有clear()方法,清除实体,不会从客户端删除EntityManager。当然,如果我认为这一切都错了,请告知更好的方法。希望我已经清楚地解释了一些事情,有人可以提供可能的解决方案。

所以,感谢PW Kad的回答,我能够重用实体管理器而不是删除和重新创建它们,方法是将它们添加到$ rootScope上的空对象集合中。已初始化(仍使用上面概述的createEmptyCopy()方法)。这允许在整个Angular应用程序中进行访问,而不会污染全局命名空间。我已经实现了一个与每个标签相关联的唯一ID - 以及内容区域中的模块 - 因此我附加了该ID以创建名称,例如'EM_' + instanceId,以便存储在{ {1}}对象。之后,我可以使用此ID找回$rootScope.entityManagers中的EntityManager实例,该ID位于每个帐户编辑器的Angular $rootScope中。

这是新代码:

Controller

虽然我仍然想知道BreezeJS保留其// NEW: Add an 'entityManagers' object to the $rootScope of my main app module angular.module('app', []) .run(['$rootScope', function($rootScope) { $rootScope.entityManagers = {}; $rootScope.entityManagers.count = 0; }]); // In the dataServices factory for the main app module var serviceName = "/breeze/accounts"; var ds = new breeze.DataService({ serviceName: serviceName, hasServerMetadata: true }); var masterManager = new breeze.EntityManager({ dataService: ds, saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: false }) }); function createManager(instanceId) { // make a copy of the above EntityManager (with no cached entities) var sandboxManager = masterManager.createEmptyCopy(); // NEW: Save the EntityManager instance to the $rootScope $rootScope.entityManagers['EM_' + instanceId] = sandboxManager; $rootScope.entityManagers.count++; return sandboxManager; } // In the event that you want to delete the EntityManager from the $rootScope function deleteManager(instanceId) { var manager = $rootScope.entityManagers['EM_' + instanceId]; manager.clear(); delete $rootScope.entityManagers['EM_' + instanceId]; $rootScope.entityManagers.count--; } // And lastly, inside any Angular controller $scope.instanceId = '1234'; // Dynamically-assigned at runtime $scope.init = function() { var manager = $rootScope.entityManagers['EM_' + $scope.instanceId]; if (manager === undefined) { $scope.entityManager = entityManagerService.createManager($scope.instanceId); } else { $scope.entityManager = manager; } } $scope.getEntityById = function(id){ //use $scope.entityManager here to query database via Breeze } 集合的位置,但我有一个有效的解决方案。我希望它可以帮助别人!

1 个答案:

答案 0 :(得分:1)

每次更改页面时重新实例化一个新的实体管理器似乎是一个糟糕的设计选择,因为实际上你正在丢失缓存机制并在页面之间共享实体但是如果你必须这样做,你总是可以相当平凡地做到这一点。像 -

var manager = {};

manager = manager ? manager.clear() : new breeze.EntityManager();

manager = manager ? (function () { delete manager; return new breeze.EntityManager(); })() : new breeze.EntityManager();

或许多其他方式。

我建议不要这样做,只是做这样的事情 -

var manager = {};

// Some route activation logic
if (!manager) {
    manager = new breeze.EntityManager();
}

修改

简而言之,我不是100%确定全局命名空间中的breeze对象是如何引用实体管理器的。我不认为breeze对象保留了一组实体管理器,但我可能错了。我不明白为什么在实体管理器上调用delete是行不通的,但这应该做你想做的事情 -

在任何一个闭包或全局命名空间中的某个位置创建一个名为entityManagers的对象。示例 -

window.entityManagers = {};
window.entityManagers.count = 0;

然后在将管理器创建到该命名空间时对其进行操作。可能有一种更动态的方法来做这个只是给出一些伪代码 -

window.entityManagers.createNewManager = function (name) {
    window.entityManagers[name] = new breeze.EntityManager();
}


window.entityManagers.createNewManager('ManagerNumber1');

然后,当您想要处理特定实例时,只需清除它然后将其删除即可。通过变量引用获取您想要的实例,或者如果由于某些疯狂的原因而无法将其从受影响的实体中删除 -

window.entityManagers.deleteManager = function (name) {
    window.entityManagers[name].clear();
    delete window.entityManagers[name];
}

window.entityManagers.deleteManager('ManagerNumber1');

对于所有意图和目的,只要在其他模块/控制器中没有对该管理器实例的其他引用/此应该从世界中删除entityManager。我仍然不完全理解用例,所以要用一点盐。