【问题标题】:UnMapped property on the Angular/Breeze SPA templateAngular/Breeze SPA 模板上的未映射属性
【发布时间】:2013-08-03 09:22:22
【问题描述】:

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

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

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

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

谢谢。

【问题讨论】:

    标签: angularjs breeze


    【解决方案1】:

    您找到解决此问题的方法了吗?我一直在努力解决同样的问题,最近发现 CassidyK 的 this SO post,他通过更改 Breeze 源代码 (breeze.debug.js) 中的一行来解决一个非常相似的问题。这是他更改的代码 sn-p(取自 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 = { };
        }
    };
    

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

    【讨论】:

    • 谢谢拉里法克斯。 CassidyK 几周前在我的帖子中写了一条评论,提到了他的解决方案,但后来他删除了它。我没有尝试他的解决方案,因为我更改了项目中的逻辑不使用未映射的属性。你用的是哪个版本的微风JS?
    • @KostasValais 我使用的是 Breeze 1.4.5,我根据上面帖子中的代码 sn-p 进行了修改。
    【解决方案2】:

    给读者一些背景知识。

    区分很重要

    • 从 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 的新实例(使用newentityManager.CreateEntity(...))时,每个ctor 的MyUnmappedProperty 属性设置为''

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

    这就是应该发生的事情。

    你能证明一个查询的TodoList曾经实现,这样它的MyUnmappedProperty 不是“testString”吗?

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

    我需要一个复制品!

    【讨论】:

      【解决方案3】:

      @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”。

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

      谢谢。

      【讨论】:

      • 您的构造函数不是在构造时将服务器返回的任何值设置为“”吗?也许我读错了,但是如果您查看 json 有效负载,它几乎可以肯定是“测试字符串”,然后您的构造函数第一次将其清除,但是由于您正在刷新已构建的实体,因此第二次是“测试字符串”
      • @PW Kad,可能这就是正在发生的事情。有没有办法在不刷新的情况下首先传递“testString”值?
      • 我不完全理解你想要做什么,但如果在某些时候 this.MyUnmappedProperty 有一个值并且你将它设置为 "" 然后检查它是否有你之前的值改变它。
      • 我想扩展实体(TodoList)客户端定义,以便在查询数据库时显示服务器端计算属性“MyNotmappedProperty”返回的值。沃德在这里用全名做了很多事情stackoverflow.com/questions/16524073/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-29
      相关资源
      最近更新 更多