【问题标题】:Breeze JS: Is there a way to query entities from data.results?Breeze JS:有没有办法从 data.results 中查询实体?
【发布时间】:2013-10-04 03:11:53
【问题描述】:

我有一个 Breeze web api 控制器,其方法可以在服务器上接受参数并执行一些工作、过滤、排序等。 在 querySucceeded 上,我想进一步查询 data.results。有没有办法做到这一点?我通过将 data.results 导出/导入到本地经理来完成这项工作,并从那里进行投影。为了在供应商网格控件中使用可观察集合,需要进行投影。

        var query = datacontext.EntityQuery.from("GetActiveCustomers")
            .withParameters({ organizationID: "1" })
            .toType("Customer")
            .expand("Organization")
            .orderBy('name');

        var queryProjection = query
                .select("customerID, organizationID, name, isActive, organization.name");

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

        function querySucceeded(data) {
            var exportData = manager.exportEntities(data.results);
            var localManager = breeze.EntityManager.importEntities(exportData);
            var resultProjection = localManager.executeQueryLocally(queryProjection); 
    //This is the way I came up with to query data.results (exporting/importing the result entities to a local manager)
    //Is there a better way to do this? Querying directly data.results. Example: data.results.where(...).select("customerID, organizationID...)

            if (collectionObservable) {
                collectionObservable(resultProjection);
            }
            log('Retrieved Data from remote data source',
                data, true);

        }

【问题讨论】:

    标签: javascript breeze single-page-application hottowel


    【解决方案1】:

    您采用了一种有趣的方法。通常,投影返回不可缓存的对象,而不是实体。但是您将其转换为 Customer(使用 toType 子句),这意味着您创建了缺少数据的 PARTIAL Customer 实体。

    我必须希望您知道自己在做什么,并且不打算在这些客户实体保持局部时保存更改,否则可能会发生灾难。

    请注意,当您将选定的客户导入“localManager”时,您并没有带上他们相关的Organization 实体。这意味着像resultProjection[0].organization 这样的表达式将返回null。这似乎不正确。

    我了解您希望保留 Customer 部分实体的子集,并且没有 本地 查询可以从缓存中选择该子集,因为选择标准仅在服务器上完全知晓。

    我想我会以不同的方式处理这种需求。

    首先,我会将所有这些逻辑隐藏在DataContext 本身中; DataContext 的目的是封装数据访问的详细信息,以便调用者(例如 ViewModels)不必了解内部情况。 DataContext 是 UnitOfWork (UoW) 模式的一个示例,这种抽象有助于将数据访问/操作问题与 ViewModel 问题隔离开来。

    然后我会将其存储在 DataContext (DC) 或 ViewModel (VM) 的命名数组中,具体取决于该子集对应用程序的兴趣是狭义还是广义。

    如果只有 VM 实例关心这个子集,那么 DC 应该返回 data.results 并让 VM 持有它们。

    我不明白您为什么要为此集合重新查询本地 EntityManager,也不明白为什么您的本地查询还应用投影......这会将非实体数据对象返回给调用者。返回(部分)客户实体有什么问题。

    您似乎打算进一步过滤客户端上的子集。嘿……这是一个 JavaScript 数组。您可以拨打stuffArray.filter(filterFunction)。

    当然,这不会为您提供类似 Breeze LINQ 的查询语法……但您真的需要吗?为什么你需要在那个集合上使用“.select”?

    如果这确实是您的需要,那么我想我理解您为什么要将结果转储到单独的 EntityManager 以供本地使用。在这种情况下,我相信您需要在查询回调方法中添加更多代码来将相关的 Organization 实体导入到本地 EM 中,以便 someCustomer.organization 返回一个值。这种方法越来越棘手,让我感到不舒服,但这是您的应用程序。

    如果您继续走这条路,我强烈建议您将其封装在 DC 或某种服务类中。我不希望我的虚拟机知道这些恶作剧。

    祝你好运。

    2013 年 10 月 3 日更新:对未映射的属性进行本地缓存查询过滤

    在上面睡觉之后,我有另一个想法给你,在这个用例中你不需要第二个 EM。

    您可以向客户端Customer 实体添加未映射的属性,并在服务器上查询“GetActiveCustomers”端点后使用子集标记设置该属性;你会在查询回调中设置标记。

    然后您可以编写一个本地查询来过滤标记值,以确保您只考虑该子集中的 Customer 对象。

    仅在本地查询中引用标记值。我不知道对标记值的远程查询过滤是否会失败或只是忽略该标准。

    您不需要单独的本地 EntityManager;主管理器中的 Customer 实体携带服务器端过滤的证据。当然,服务器永远不必处理您未映射的属性值。

    是的,轻而易举的本地查询可以针对未映射的属性以及映射的属性。

    这是一个小演示。像这样注册一个自定义构造函数:

    function Customer() { /* Custom constructor ... which you register with the metadataStore*/
        // Add unmapped 'subset' property to be queried locally.
        this.subset = Math.ceil(Math.random() * 3); // simulate values {1..3}
    }
    

    稍后您在本地查询它。以下是引用和不引用该属性的查询示例:

    // All customers in cache
    var x = breeze.EntityQuery.from("Customers").using(manager).executeLocally();
    
    // All customers in cache whose unmapped 'subset' property === 1.
    var y = breeze.EntityQuery.from("Customers")
            .where("subset", 'eq', 1) // more criteria; knock yourself out
            .using(manager).executeLocally();
    

    我相信您会知道如何在您对“GetActiveCustomers”查询的回调中适当地设置subset 属性。

    HTH

    【讨论】:

    • 在微风控制器中,“GetActiveCustomers”从实体框架返回 IQueryable 实体:它不返回部分客户。我昨晚删除了 toType("Customer"),并添加了这个: manager.metadataStore.setEntityTypeForResourceName("GetActiveCustomers", "Customer");我的微风控制器有几个从实体框架返回 IQueryable 的方法。这就是为什么我在使用任何这些资源或使用 setEntityTypeForResourceName ( resourceName entityTypeOrName ) 时必须使用 toType 的原因。
    • 关于您关于为什么我需要重新查询返回的客户实体集的问题,是做一个投影 (.select("column1, column2, etc")) 以在供应商网格中显示信息控制,只需拥有一个带有我在投影中使用的属性的淘汰 observable 集合(更多信息:breezejs.com/documentation/knockout-circular-references)。
    • 这两个答案对我来说都很有意义。我在更新中给你另一个想法
    • 我会试试你的方法,让你知道结果如何。我认为它会工作得很好。万一您想知道,我们采用这种方法的原因是因为我们在业务线应用程序(使用热毛巾模板的单页应用程序、Windows Phone、Windows 8 应用程序)中针对多个客户端,所以我们有服务器上的代码不仅可以在微风控制器中重用,还可以在常规 Web api 控制器等中重用。
    • 我们有供应商网格控件(Kendo UI Web 控件),主要包含三个过滤选项(Active、Inactive、All),它们通过调用资源名称来加载实体,例如“GetActiveCustomers”、“GetInactiveCustomers”、“GetAllCustomers” ”。你认为这是处理这个问题的最聪明的方法吗?通过使用“this.subset”等客户端属性标记加载的实体?非常感谢您对此的意见。
    【解决方案2】:

    一旦您查询了一些数据,轻而易举地将这些实体存储在本地内存中。

    当您需要进一步过滤数据时,您只需在本地查询即可。 您可以通过指定经理在本地查询来做到这一点:

    manager.executeQueryLocally(query);
    

    因为从数据库中查询是异步完成的,所以您必须确保只有在本地内存中有内容时才从本地内存中检索。遵守诺言。

    【讨论】:

    • 问题是服务器端函数“GetActiveCustomers”完成了所有工作。一旦它们被缓存,客户端中就没有代码可以再次找到这些对象。当实体在 querySucceeded 上加载和缓存时,最近加载的实体将与其余缓存的实体合并。我想从 data.results 中执行 .selects、.where 等,而不是查询本地数据以再次找到这些对象。
    • 你能提供更多关于你想要做什么的细节吗?
    • 我正在尝试做的是:data.results.select("customerID, organizationID, name") on the querySucceeded。
    • data.results 是一个包含所有检索到的条目的数组。您可以做的是使用 JavaScript 过滤更多内容并仅返回您需要的内容。例如:一个条目具有以下dependentObservables:"customerID, name, isActive, organization.name"。您可以将所需的 "customerID, name" 封装在不同的数组中并返回该数组。如果你遍历数组,你甚至可以再次过滤它们,让我们说:if(data.results[index].customerID()===1) newArray.push({customerID: data.results[index].customerID}, ...);
    猜你喜欢
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多