UnMapped property on Angular / Breeze SPA template

I use the Angular / Breeze SPA template in visual studio 2012. I added the unmapped property in the TodoList server model.

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

I registered the unmapped property in the constructor on the client model, in particular in todo.model.js, for example, Ward: Processing calculated properties using breezejs and web api

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

When the getTodos () method is called in todo.controller.js for the first time, "myUnmappedProperty" has the empty string value specified in the constructor. Only after getTodos () is called a second time (I added a button that does this), with the forceRefresh parameter set to true (getTodos (true)) to request the server, only then can I see that myUnmappedProperty gets the value " CompareString ".

I am wondering why I get this behavior. Is it possible for a name without a name to be populated with the server value the first time getTodos () is called?

Thanks.

0
source share
3 answers

Did you find a solution to this problem? I struggled with the same problem and recently found this SO post from CassidyK in which it solves a very similar problem by changing one line in the Breeze source code (breeze.debug.js). Here is a snippet of the code that he changed (taken from a CassidyK post):

 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 = { }; } }; 

I tried this solution and it seems to work fine. Note that this change is likely to cause you problems if you ever have a case where you have a server-side property that does not appear in the database and you want the client side to overwrite this value when an object is created on the client side.

+2
source

Some background for the reader.

Important to distinguish

  • "unmapped" in terms of EF
  • not serialized from the perspective of Json.Net
  • "unmapped" in terms of the breeze

[NotMapped] is an EF attribute that tells EF "this property does not map to the database."

[JsonIgnore] is a Json.Net attribute that tells JSON.Net "Do not serialize this property when sending it to the client"

Only metadata can tell Breeze which properties are "mapped" ... from his point of view.

A breeze usually ignores incoming properties that are defined in metadata. However, if a property other than metadata is defined in the constructor, Breeze adds it to the metadata and classifies it as "unmapped".

For Breeze, this means "serialize this property, notify the user interface when it changes, but this is not part of the entity's data model and changes should not be tracked (i.e. changes to it do not affect EntityState)."

Combine these ideas to understand your question .

You told EF not to display the MyUnmappedProperty property. You are EFContextProvider using EFContextProvider to generate metadata so that the property is also not in the metadata.

But Json.Net is not aware of this. Therefore, whenever it serializes an instance of your TodoList , it sends the MyUnmappedProperty ("testString") property to the Breeze client.

At first Breeze will do nothing with it. If the server sends this property with any value, Breeze will ignore it.

But you added the MyUnmappedProperty property to the constructor of the TodoList type, so now Breeze recognizes this property as "unmapped" and materializes its value if it appears in the results of a JSON request.

When you create a new TodoList instance (with new or entityManager.CreateEntity(...) ), then the MyUnmappedProperty property MyUnmappedProperty set to '' on ctor.

When you request TodoList , Json.NET sends {MyUnmappedProperty: "testString} to the JSON results. The Breeze client recognizes MyUnmappedProperty and accordingly sets this property on the materialized instance of the TodoList entity.

What is about to happen.

Can you demonstrate that the requested TodoList ever materialized in such a way that its MyUnmappedProperty not a "testString"?

You checked the network traffic, and you see that {MyUnmappedProperty: "testString} actually goes through the cable but doesn’t materialize? And you say that this is materialized in the second request ?.

I need to reproduce this!

+1
source

@Ward, Thanks for your reply.

First of all, I forgot to mention that I am using Breeze version 1.4.0.

You checked the network traffic, and you see that {MyUnmappedProperty: "testString} actually goes through the cable: Yes, I checked it and included it in the JSON sending from the server.

To create the behavior I'm experiencing, 3 small additions to the spa template are required.

In todo.view.html I add the button "myGetBtn" and span "mySpan" with an angular binding:

 ... <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> ... 

In the .Net POCO TodoList class add

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

In todo.model.js I modify the constructor as follows:

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

Now, if you started the application and successfully logged in, {{list.MyNotMappedProperty}} shows an empty line, if you then click the "Get Todos" button, {{list.MyNotMappedProperty}} displays the value "testString".

In both cases, the request is the same and returns 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"}}]}] 

I would like to get the "testString" shown first without pressing the button that I added.

I don't know if the information I provided is enough to reproduce the behavior, so please tell me if you need more information.

Thanks.

0
source

Source: https://habr.com/ru/post/973567/


All Articles