breezejs createEntity未定义

时间:2013-04-19 11:08:04

标签: angularjs breeze angularjs-directive

在AngularJS指令中,我为范围变量指定了一个新值:

$scope.myPerson = { TiersId: 105191, Name: "John Smith" };

原来$ scope.myPerson是从BreezeJS实体创建的。

分配新值会触发AngularJS的$ scope.apply(),然后由BreezeJS拦截。那就是它变得复杂的时候。

[编辑]

好的,我已经发现我需要使用我在dataContext中注册的EntityManager:

$scope.myPerson =  myDataContext.createPerson({ TiersId: 105191, Name: "John Smith" });

  function createPerson(person) {
        return manager.createEntity("AccountOwner", person);
  }

现在,它在以下代码中失败:

  proto.createEntity = function (typeName, initialValues, entityState) {
    entityState = entityState || EntityState.Added;
    var entity = this.metadataStore
        ._getEntityType(typeName)
        .createEntity(initialValues);
    if (entityState !== EntityState.Detached) {
        this.attachEntity(entity, entityState);
    }
    return entity;
};

实体类型是已知的,但createEntity(initialValues)函数未定义。怎么会 ?

[编辑]

为了使事情更清楚,这里是相关的EF映射以及模型类:

public class MandateMappings : EntityTypeConfiguration<Mandate>
{
    public MandateMappings()
    {
        Property(m => m.IBAN).HasMaxLength(34).IsFixedLength().IsUnicode(false);

        Property(m => m.AccountOwner.Name).HasMaxLength(70);  
        Property(m => m.AccountOwner.City).HasMaxLength(500); 

        Property(m => m.CreatedBy).HasMaxLength(30);
        Property(m => m.UpdatedBy).HasMaxLength(30);
    }
}



public class Mandate : Audit
{  
    public string IBAN { get; set; }

    public AccountOwner AccountOwner { get; set; }

}

public class AccountOwner
{
    public string Name { get; set; }
    public string City { get; set; }
}

public abstract class Audit
{
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
}

2 个答案:

答案 0 :(得分:1)

编辑:从v 1.3.1开始,Breeze现在支持继承。

没有更多的上下文我不能确定,但​​我猜测问题是Breeze不会有关于你的entityType的元数据。通常这是通过您的第一个查询完成的,但如果您在第一个查询之前创建实体,则替代方法是在执行任何createEntity调用之前调用 EntityManager.fetchMetadata()方法。 fetchMetadata 方法是异步的,即返回一个promise,因此您需要在promise的'then'部分内执行createEntity调用。最近有一些与此类似的“微风”帖子有更多细节和例子。

答案 1 :(得分:1)

让我澄清一下,当{4}} Breeze支持一种继承形式但不支持“数据库继承”时我的意思。

我的意思是,今天,服务器端的类可以成为继承链的一部分,当且仅当该链对客户端不可见时

以下是与该警告一致的一些条件:

  • 只有链中的“terminal”类(派生程度最高的类)才会映射到数据库表。

  • 超类的属性是非公开的(例如,内部的)或显式未映射的(例如,用[System.ComponentModel.DataAnnotations.Schema.NotMapped]装饰。

  • 方法可以出现在任何级别的任何级别,因为这些方法永远不会传输到客户端。

以下是继承自TodoItem的{​​{1}}类的示例:

public class baseClass
{
    public void DoNothing() {}
    internal string Foo { get; set; }
}
public class TodoItem :baseClass
{
    public int Id { get; set; }                   

    [Required, StringLength(maximumLength: 30)]   
    public string Description { get; set; }       

    public System.DateTime CreatedAt { get; set; }
    public bool IsDone { get; set; }              
    public bool IsArchived { get; set; }          
}

这在服务器上运行正常。在控制器中设置一个断点:执行baseClass并获取/设置DoNothing()属性没有问题。

这是有效的,因为此结构没有客户端后果。从Foo推导出来之后,元数据与以前没有什么不同。 baseClass属性和Foo方法对客户端不可见......与此服务作者的目标完全相同。

这种安排在现实世界中很常见,其中商业模型的许多类通过基类共享功能。

这不是故事的结局,并不是我们认为人们在要求“继承”时所要求的。

我们认为人们想要我所谓的“数据库继承”,我的意思是继承链中的两个或更多类被映射到不同的表。

今天Breeze没有处理这个问题......部分是因为Breeze还不能理解描述继承层次结构的元数据。

解决方法

如果您有一个类层次结构,其中数据属性是在不同的类级别定义的,那该怎么办?您可以通过提供从客户端角度展平层次结构的元数据描述来解决当前障碍。

例如,假设您的DoNothing类型为PersonFirstNameLastName派生自Person,定义entityBase

如果您将 Person * EntityType *定义为具有[createdByFirstNameLastName]属性 - 基本上扁平化层次结构 - 所有将是好。

自动展平层次结构

当然那是PITA。我们可以采取的一种继承方法是,当您要求Breeze在服务器上生成元数据时,为您执行此展平。

我很好奇:这还够吗?或者您真的需要在JavaScript客户端上知道createdBy属性属于基类。如果你真的需要知道,请告诉我原因。