从EntityQuery获取纯JavaScript对象(对于大型结果集)?

时间:2013-06-10 05:48:43

标签: breeze

Breeze很精彩,但我们遇到了大型结果集的内存问题。我知道自己想要达到的目标,并且会重视对最佳方法的任何想法......

  • 对于特殊(大)结果集,我想让Breeze像正常一样对服务器服务执行查询但不将这些结果转换为实体 - 而是删除额外的“Breeze”JSON并给我JavaScript对象的简单列表(理想情况下,属性框更改为适合客户端)。

  • 然后我可以将这些结果放入ObservableArray并使用Knockout绑定它们 - 但是没有可观察或跟踪的每个属性的开销。

  • 当用户表示他们想要编辑记录时,我可以创建一个合适的Breeze实体并将其拼接到ObservableArray中代替普通的Javascript对象。只要属性名称完全匹配,那么Knockout绑定就不应该更明智了。

  • 然后,Breeze可以跟踪更改并为实际编辑的少数记录提供正常的保存。

我希望保留Breeze的一些价值,但要避免这些大型结果集的开销。具体来说,我想尽可能避免创建自定义(非Breeze)服务器端控制器方法。

任何人都可以建议进入Breeze的最佳地点试图实现这一目标吗? (或更好的方法)

感谢您提出任何意见。

2 个答案:

答案 0 :(得分:1)

基本上Breeze只会为任何具有元数据中描述的实体类型的json创建'observable'。当breeze解析任何查询的传入结果时,它会尝试“识别”json有效负载中返回的任何entityTypes,如果不能,那么它只返回原始形式的json对象。此解析由'default' JsonResultsAdapter 执行。

这意味着如果您不告诉Breeze 关于大型结果集中的'entityTypes',那么您将获得所需的结果。 Breeze在对服务器的初始元数据调用期间获取这些entityType'定义'。对于涉及实体框架的模型,将自动为模型中描述的任何类型提供这些类型。这意味着您创建的任何DTO都不具有entityTypes,除非您明确提供了元数据。因此,一种选择是简单地将大型结果集作为DTO返回。

另一个可能更好的选择是,如果这些大型结果集包含breeze确实知道的entityTypes,但您只想忽略它们以进行特定查询。在这种情况下,最好的选择是为这些只返回entityType的查询编写自定义JsonResultsAdapter。像这样:

   var customJsonResultsAdapter = new breeze.JsonResultsAdapter({
        name: "ignoreEntityTypeAdapter",

        visitNode: function (node, mappingContext, nodeContext) {
            return {  };
        }
    });

    var query = EntityQuery.from("QueryThatResultsLargeResultSet")
         .where(...)
         .using(customJsonResultsAdapter);

希望这很清楚。

答案 1 :(得分:0)

根据上面的评论,我们在使用customJsonResultsAdapter方法时错过了Breeze连接所有导航属性等。基本上我们想要Breeze的优点,而不需要将所有实体属性设置为Knockout observable(直到我们需要它们为止)。

编辑:由于以前的自定义modelLibrary方法中的错误,答案已更改为使用两个实用程序函数

作为替代解决方案,我们更改为使用内置的Breeze backingStore modelLibrary 适配器并添加了一些函数,以便在需要时使单个实体 Knockout observable 。其后果是:

  • 这是一种“精简”方法,是只读数据的理想选择。
  • Breeze 拦截对这些属性的更改并像平常一样跟踪它们。
  • 我们仍然可以使用Knockout绑定 lite 实体,但由于默认情况下属性不可观察,因此如果属性值发生更改,网页将不会更新。

当用户想要编辑实体时,我们会执行类似......

的操作
    function startEditing(entity, uiElement) {
        if (!breeze.utils.isObservable(entity)) {
            breeze.utils.makeObservable(entity);
            ko.applyBindings(entity, uiElement);
        }

一些重要的注意事项:

  • 我们需要在使实体可观察后重新applyBindings,以便属性更改触发Knockout更新UI。
  • 我们的makeObservable函数使用Steve Sanderson's ES5 plugin因此我们的标记绑定中不需要括号(尽管仅限于IE9 +)

我在下面列出了自定义函数的代码。在上面加载Knockout,Breeze和Steve的插件后,您需要包含此代码。

// Add a function to make an individual Breeze entity observable.
// Requires the Knockout ES5 plugin from http://blog.stevensanderson.com/2013/05/20/knockout-es5-a-plugin-to-simplify-your-syntax/
// Note: Breeze must be configured to use it's built in backingStore adapter: 
//     breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);

(function () {

    var utils = breeze.utils = breeze.utils || {};

    utils.makeObservable = function (entity) {
        var bs = entity && entity._backingStore;
        if (!bs) {
            throw new Error("Only entities provided by the backingStore adapter can be made observable");
        }
        ko.track(bs);
    };

    utils.isObservable = function (entity) {
        var result = false,
            bs = entity && entity._backingStore;
        if (bs) {
            var propNames = Object.getOwnPropertyNames(bs);
            if (propNames.length > 0) {
                result = !!ko.getObservable(bs, propNames[0]);
            }
        }
        return result;
    };

})();