Breeze使用DB EntityTypes管理NODB EntityTypes

时间:2013-05-06 05:43:11

标签: breeze

我正在使用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()
     }

然后在success方法中的primeData中调用this:

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

其中getLocal是:

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

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

我做错了什么?

由于

2 个答案:

答案 0 :(得分: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 /资源名称

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

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

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

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

[Get]
public IQueryable<Foo> Foos() {...}

现在,如果您进行如下查询:

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

并将其应用于缓存

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

它只是有效。

为什么呢?因为

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

端到端的约定默默地对你有利。

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

注册资源名称

没问题!

您可以按如下方式添加自己的资源到实体类型的映射:

var metadataStore = manager.metadataStore;
var typeName = 'some-type-name';
var entityType = metadataStore.getEntityType(typeName);

metadataStore.setEntityTypeForResourceName(resource, entityType);

Breeze也很满意这个类型的名称:

metadataStore.setEntityTypeForResourceName(resource, typeName);

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

var metadataStore = manager.metadataStore;
// map two resource names to Esto
metadataStore.setEntityTypeForResourceName('Esto', 'Esto'); 
metadataStore.setEntityTypeForResourceName('Informacion', 'Esto');

不要过度使用toType()

当您需要将查询结果中的顶级对象映射到toType()时,EntityType方法是一个很好的快捷方法。您不必乱用注册资源名称。

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

注释

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

答案 1 :(得分: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);

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

另请注意,单个实体类型可以包含任意数量的resourceNames。只需确保在尝试本地查询之前注册resourceNames。