Angular / Breeze SPA模板上的UnMapped属性

时间:2013-08-02 07:31:37

标签: angularjs breeze

我在visual studio 2012中使用Angular / Breeze SPA模板。我在TodoList服务器模型中添加了一个未映射的属性。

[NotMapped]
public string MyUnmappedProperty{ get{return "testString";}} 

我在客户端模型的构造函数中注册了未映射的属性,特别是在Ward建议的todo.model.js中:Handling calculated properties with breezejs and web api

function TodoList() {
        this.title = "My todos"; // defaults
        this.userId = "to be replaced";
         this.myUnmappedProperty="";
    }

第一次在todo.controller.js上调用getTodos()方法时,“myUnmappedProperty”具有构造函数中设置的空字符串的值。只有在第二次调用getTodos()之后(我添加了一个执行该操作的按钮)并将'forceRefresh'设置为true(getTodos(true))才能查询服务器,只有这样才能看到myUnmappedProperty获取值“的TestString”。

我想知道为什么我会得到这种行为。是否可以在第一次调用getTodos()时使未映射的属性填充服务器值?

谢谢。

3 个答案:

答案 0 :(得分:2)

您找到了解决此问题的方法吗?我一直在努力解决同样的问题,最近才发现了CassidyK的this SO post,他在Breeze源代码(breeze.debug.js)中改变了一行来解决一个非常类似的问题。这是他改变的代码片段(取自CassidyK的帖子):

proto.initializeFrom = function (rawEntity) {
    // HACK:
    // copy unmapped properties from newly created client entity to the rawEntity.
    // This is so that we don't lose them when we update from the rawEntity to the target.
    // Something that will occur immediately after this method completes. 
    var that = this;
    this.entityType.unmappedProperties.forEach(function(prop) {
        var propName = prop.name;
        that[propName] = rawEntity[propName];  // CassidyK 
        //rawEntity[propName] = that[propName]; // Breeze 
    });

    if (!this._backingStore) {
        this._backingStore = { };
    }
};

我尝试过这个解决方案,似乎工作正常。请注意,如果您遇到的情况是您的服务器端属性未映射到数据库中,并且在客户端创建对象时需要客户端覆盖此值,则此更改可能会让您遇到麻烦。

答案 1 :(得分:1)

读者的一些背景知识。

区分

非常重要
    来自EF视角的
  • “unmapped”
  • 从Json.Net视角“未序列化”
  • 从Breeze视角“取消映射”

[NotMapped]是一个EF属性,告诉EF“此属性未映射到数据库”。

[JsonIgnore]是一个Json.Net属性,它告诉JSON.Net“在将该属性发送到客户端时不会序列化此属性

只有元数据可以告诉Breeze从哪个角度“映射”...

Breeze通常会忽略元数据中定义的传入属性。但是,如果构造函数中定义了非元数据属性,Breeze会将其添加到元数据并将其分类为“未映射”。

对于Breeze,这意味着“序列化此属性,在更改时通知UI,但这不是实体数据模型的一部分,不应进行更改跟踪(即,对其进行更改不会影响EntityState) )。

让我们将这些想法放在一起以理解您的问题

你告诉EF不要映射MyUnmappedProperty属性。您可能正在使用EFContextProvider生成元数据,以便属性也不在元数据中。

但是Json.Net并不知道这些。因此,无论何时序列化TodoList的实例,它都会将MyUnmappedProperty属性(“testString”)发送给Breeze客户端。

起初Breeze不会对它做任何事情。如果服务器使用任何值发送此属性,Breeze将忽略它。

但是您将MyUnmappedProperty属性添加到TodoList类型构造函数中,因此现在Breeze会将此属性识别为“unmapped”,并且如果它出现在JSON查询结果中,它将实现其值。

当您创建TodoList的新实例(newentityManager.CreateEntity(...))时,MyUnmappedProperty属性设置为每个ctor ''。< / p>

当您查询TodoList时,Json.NET会在JSON结果中发送{MyUnmappedProperty: "testString}。 Breeze客户端识别MyUnmappedProperty,并相应地在物化TodoList实体实例上设置该属性。

这就是应该发生的事情。

您是否可以证明查询的TodoList 是否已实现,以使其MyUnmappedProperty不是“testString”?

您已检查过网络流量,但您发现{MyUnmappedProperty: "testString}实际上是通过网络传输但未实现?你说它是在第二个查询中实现的吗?

我需要一个责备!

答案 2 :(得分:0)

@Ward,谢谢你的回答。

首先,我忘了提到我使用的是Breeze 1.4.0版。

您已经检查了网络流量,并且您看到{MyUnmappedProperty:“testString}实际上正在通过网络:是的我已经检查过它并且包含在来自服务器的JSON发送中

spa模板需要3个小的附加内容才能获得我遇到的行为。

todo.view.html我添加按钮“myGetBtn”和带有角度绑定的范围“mySpan”:

...
<button data-ng-click="addTodoList()">Add Todo list</button>
<br/>
<p>
    <button id="myGetBtn" ng-click="getTodos(true)">Get todos</button>
</p>
<article class="todoList" data-ng-repeat="list in todoLists">
    <header>
        <form data-ng-submit="endEdit(list)">
            <span id="mySpan">myNotMappedProperty: {{list.MyNotMappedProperty}}</span>
            <input  data-ng-model="list.title" 
                    data-selected-when="list.isEditingListTitle"
                    data-ng-click="clearErrorMessage(list)" 
                    data-on-blur="endEdit(list)"/>           
        </form>
    </header>
...

在.Net POCO类TodoList中我添加

[NotMapped]
public string MyNotMappedProperty { get { return "testString"; } }

todo.model.js我修改构造函数如下:

function TodoList() {
        this.title = "My todos"; // defaults
        this.userId = "to be replaced";
        this.MyNotMappedProperty = "";
    }

现在,如果您运行应用程序并成功登录,{{list.MyNotMappedProperty}}会显示空字符串,如果您再按“获取待办事项”按钮,{{list.MyNotMappedProperty}}会显示值“testString”。

在这两种情况下,查询都是相同的,返回的Json如下:

[{"$id":"1","$type":"TodoTest.Models.TodoList, TodoTest","TodoListId":5,"UserId":"kostas","Title":"My todos","MyNotMappedProperty":"testString","Todos":[{"$id":"2","$type":"TodoTest.Models.TodoItem, TodoTest","TodoItemId":4,"Title":"dasdas","IsDone":false,"TodoListId":5,"TodoList":{"$ref":"1"}}]}]

我想在没有按下我添加的按钮的情况下首先显示“testString”。

我不知道我提供的信息是否足以重现行为,所以如果您需要任何其他信息,请告诉我。

谢谢。