4

我正在使用 Papa 的课程 CCJS 代码来研究 Breeze.js 和 SPA。使用此代码,我试图管理来自服务器的附加信息,但它不是来自 EntityFramework 的元数据中包含的实体。

所以我创建了一个名为 Esto 的 NO-DB 类和一个像 Lookups 这样的服务器方法:

  [HttpGet]
  public object Informacion()
    {
       var a = new Esto(....);
       var b = new Esto(.....);
       var c = new Esto(......);

    return new {a,b,c};
    }

然后在configureMetadataStore里面的model.js中我调用:

metadataStore.addEntityType({
    shortName: "Esto",
    namespace:"CodeCamper",
    dataProperties:{
      id: {dataType: breeze.DataType.Int32,isPartOfKey: true},
      name: {dataType: breeze.DataType.String}
      }
   };

并且还在模型 entityNames 数组中定义: esto:'Esto' 作为实体

现在在 context.js 中,我加载了它,创建了一个服务器端方法,例如 getLookups,但称为 getInformacion:

    function getInformacion(){
            return EntityQuery.from('Informacion')
                   .using(manager).execute()
     }

然后在成功方法中的 primeData 内部调用:

datacontext.informacion = {
    esto: getLocal('Esto',nombre)};

其中 getLocal 是:

  function getLocal(resource, ordering)
   {
        var query = EntityQuery.from(resource).orderBy(ordering);
        return manager.executeQueryLocally(query);
   }

我在 getLocal 中包含的查询中收到一个错误,指出无法找到 entityTypeName:'undefined' 或 resourceName:'Esto' 的 EntityType。

我做错了什么?

谢谢

4

2 回答 2

10

你快到了!:-) 如果您EntityType在查询中指定了目标,我认为它会起作用。

尝试这个:

var query = EntityQuery.from(resource).orderBy(ordering)。toType('Esto') ;

toType()方法告诉 Breeze 此查询返回的顶级对象将是 类型Esto

为什么?

让我们考虑一下 Breeze 如何解释查询规范。

请注意,正如我们通常所做的那样,您通过命名将提供数据的资源来开始查询。此资源通常是到远程服务端点的路径段,可能是 Web API 控制器方法的名称……一个名为“Foos”的方法。

了解查询资源名称很少与EntityType名称相同是至关重要的! 它们可能相似——“Foos”(复数)类似于类型名称“Foo”(单数)。但资源名称可能是别的东西。它可能是“GetFoos”或“GreatFoos”或任何东西。重要的是服务方法返回“Foo”实体。

Breeze 需要一种将资源名称与EntityType名称相关联的方法。Breeze 本身并不知道相关性。该toType()方法是告诉 Breeze 的一种方式。

为什么没有远程查询toType()

您通常不会添加toType()到您的查询中。为什么现在?

大多数时候 [1],Breeze 不需要知道EntityType 直到数据从服务器到达之后。当 JSON 查询结果包含类型名称时(例如,当它们来自 Breeze Web API 控制器时),Breeze 可以在没有我们帮助的情况下将到达的 JSON 数据映射到实体中……假设这些类型名称在元数据中。

本地缓存查询不同

当您查询缓存时...说executeQueryLocally... Breeze 必须知道要搜索哪个缓存实体集才能在本地查询

它“知道”您是否使用toType(). 但是,如果您省略toType(),Breeze 必须使用查询的资源名称。

微风猜不透。相反,它会在 EntityType/ResourceName 映射中查找与查询资源名称匹配的实体集。

资源名称指的是服务端点,而不是缓存的实体集。例如,没有名为“Informacion”的实体集。因此 Breeze 使用EntityType/ResourceName映射来查找与查询资源名称关联的实体类型。

实体类型/资源名称

EntityType/ResourceName映射是 Breeze 中的项目之一MetadataStore。你可能从未听说过它。那挺好的; 你不应该考虑它......除非你做一些不寻常的事情,比如定义你自己的类型。

一个新的地图MetadataStore开始是空的。如果这些元数据包含 EntityType/Resource 映射,Breeze 会从服务器元数据中填充它。

例如,Breeze使用从名称EFContextProvider派生的映射生成元数据。DbSet当您定义一个Foo类并将其从 a 公开DbContextDbSet命名的“Foos”时,EFContextProvider元数据生成器会添加从“Foos”资源名称到Foo实体类型的映射。

控制器开发人员倾向于使用DbSet名称作为方法名称。传统的 Breeze Web API 控制器“Foo”查询方法如下所示:

[得到]
公共 IQueryable<Foo> Foos() {...}

现在,如果您进行这样的查询:

var query = EntityQuery.from('Foos').where(...);

并将其应用于缓存

manager.query.executeLocally(query).then(...);

它只是工作。

为什么?因为

  • “Foos”是DbSet服务器上的名称
  • 生成的EFContextProvider元数据映射 ["Foos" 到Model.Foo]
  • Web API 控制器提供了一种Foos操作方法。
  • BreezeJSquery指定“Foos”
  • executeLocally方法在元数据中找到 ["Foos"-to- Model.Foo] 映射,并将查询应用于 的实体集Foo

端到端的约定默默地为您服务。

...直到您提到不在 EntityType/ResourceName 映射中的资源名称!

注册资源名称

没问题!

您可以添加自己的资源到实体类型的映射,如下所示:

var metadataStore = manager.metadataStore;
var typeName = '一些类型名称';
var entityType = metadataStore.getEntityType(typeName);

metadataStore.setEntityTypeForResourceName(resource, entityType);

Breeze 也对类型的名称感到满意:

metadataStore.setEntityTypeForResourceName(resource, typeName);

在你的情况下,在你的顶部附近的某个地方DataContext,你可以写:

var metadataStore = manager.metadataStore;
// 将两个资源名称映射到 Esto
metadataStore.setEntityTypeForResourceName('Esto', 'Esto');
metadataStore.setEntityTypeForResourceName('Informacion', 'Esto');

不要过度使用toType()

toType()您需要将查询结果中的顶级对象映射到EntityType. 您不必为注册资源名称而烦恼。

但是,您必须记住添加toType()到需要它的每个查询。使用资源到实体类型的映射配置 Breeze 元数据,您每次都会获得所需的行为。

笔记

[1] “大多数时候,Breeze 不需要知道EntityType直到数据从服务器到达之后。 ” 一个重要的例外——超出本讨论的范围——是查询过滤器涉及日期/时间时。

于 2013-05-06T23:43:10.033 回答
1

我认为这里的问题是您假设实体类型名称和资源名称是同一件事。资源名称是用于执行查询的名称

var q = EntityQuery.from(resourceName);

在您的情况下,“resourceName”是“Informacion”,而 entityType 实际上是“Esto”。Breeze 能够在远程查询上建立这种连接,因为它可以检查作为查询“Informacion”的结果从服务器返回的结果,并看到它们实际上是“Esto”实例。这对于本地查询是不可能的,因为 Breeze 不知道从哪个本地集合开始。

在这种情况下,您需要通过MetadataStore.setEntityTypeForResourceName方法为 Breeze 提供更多信息。像这样的东西:

var estoType = manager.metadataStore.getEntityType("Esto");
manager.metadataStore.setEntityTypeForResourceName("Informacion", estoType);

请注意,如果资源是通过实体框架元数据定义的,则这实际上不是必需的,因为 Breeze 会自动将所有 EF EntitySet 名称与资源名称相关联,但此信息不适用于 DTO。

另请注意,单个实体类型可以拥有任意数量的资源名称。只需确保在尝试本地查询之前注册资源名称。

于 2013-05-06T21:59:06.493 回答