0

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

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

我已经在客户端模型的构造函数中注册了未映射的属性,特别是在 todo.model.js 中,就像 Ward 在这里建议的那样:使用breathjs和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 获取值“测试字符串”。

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

谢谢你。

4

3 回答 3

2

你找到解决这个问题的方法了吗?我一直在努力解决同样的问题,最近才发现CassidyK 的这篇 SO 帖子,他通过更改 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 = { };
    }
};

我已经尝试过这个解决方案,它似乎工作得很好。请注意,如果您有一个未映射到数据库中的服务器端属性,并且在客户端创建对象时需要客户端覆盖此值,则此更改可能会给您带来麻烦。

于 2013-11-07T09:18:39.940 回答
1

给读者一些背景知识。

区分很重要

  • 从 EF 的角度来看“未映射”
  • 从 Json.Net 的角度来看“未序列化”
  • 从微风的角度“未映射”

[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 会将此属性识别为“未映射”,并且如果它出现在 JSON 查询结果中,它将实现其值。

当您创建TodoList(with newor entityManager.CreateEntity(...)) 的新实例时,MyUnmappedProperty属性将设置为''每个 ctor。

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

这就是应该发生的事情。

你能证明一个查询曾经TodoList物化,以至于它MyUnmappedProperty不是“testString”吗?

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

我需要一个复制品!

于 2013-08-03T21:00:15.213 回答
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}},则会显示空字符串,如果您随后按下“Get Todos”按钮,则会 {{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”。

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

谢谢你。

于 2013-08-06T12:43:14.207 回答