Note that there are some explanatory texts on larger screens.

plurals
  1. POBreeze child entities within observablearray not being created as "dependentobservable"
    text
    copied!<p>Hmm. Seems wrong to me. I have a breeze query that does this:</p> <pre><code> var query = new breeze.EntityQuery() .from("AllGames") .expand("Sets, MVP, TeamerMVP.Person") .orderBy("GameDateTime desc"); </code></pre> <p>(There can be none or many TeamerMVP records per game and there is a one to one relationship with the person table, hence the expand statement for TeamerMVP.Person so I can directly access the "Name" property in person. This works perfectly in the directly one-to-one related MVP (of which there can only be one per game))</p> <p>and all seems fine - the related entities are loaded and I can access the child entities in prototype functions alright as well. However I get problems trying to do much within the html bindings with the child entities and, on checking in chrome's console, it appears it may be because the child entities, unlike the parent, are not declared as dependentobservable, they are just plain "objects".</p> <pre><code>viewmodel defines parent as: games = ko.observableArray([]) </code></pre> <p>Evaluation in console:</p> <pre><code>$data Object games: Object[0] _latestValue: Array[7] 0: Game 1: Game 2: Game &gt;GameDateTime: function dependentObservable() { &gt;HomeGame: function dependentObservable() { &gt;ID: function dependentObservable() { &gt;LeagueGame: function dependentObservable() { &gt;MVP: function dependentObservable() { &gt;MVP_PersonID: function dependentObservable() { &gt;NLorRL: "&lt;strong&gt;NL&lt;/strong&gt; (A)" &gt;Opponent: function dependentObservable() { &gt;Sets: Object[0] &gt;TeamerMVP: Object[0] </code></pre> <p>In the expanded node you can see that the parent entity-level properties (GameDateTime, HomeGame, etc.) are created as dependentobservables but the child entities (Sets, TeamerMVP) are not and I'm guessing this is why I'm having some trouble in the html template bindings doing things like "foreach" as knockout simply doesn't seem to see those child entities.</p> <p>Is there something I'm missing? Should I be creating a "games.Sets = ko.observableArray([])" declaration in the viewmodel to act as a container for the child entity when it's created?</p> <p>The json data returned shows the following:</p> <pre><code>TeamerMVP: [{$id:20, $type:lbD.model.TeamerMVP, lbD.model, GameID:3, PersonID:4,…}] 0: {$id:20, $type:lbD.model.TeamerMVP, lbD.model, GameID:3, PersonID:4,…} $id: "20" $type: "lbD.model.TeamerMVP, lbD.model" GameID: 3 Person: {$id:21, $type:lbD.model.Person, lbD.model, ID:4, Name:Mike Connor, isAdmin:false,…} PersonID: 4 </code></pre> <p>and it's easy to see the "Name" property within the related Person table.</p> <p>Edited to add: It's just the "TeamerMVP" relationship that is troublesome. Just managed to do something with a "forEach" on the "Sets" entity so that's working fine, even though it's not a dependentobservable.... I'm puzzled.</p> <p>Further edited for Ward's question:</p> <p>At breakpoint as requested I see these listed:</p> <pre><code>breezeConfig.manager.metadataStore._structuralTypeMap Object &gt;Game:#lbD.model: ctor &gt;GameSet:#lbD.model: ctor &gt;Person:#lbD.model: ctor &gt;TeamerMVP:#lbD.model: ctor &gt;Venue:#lbD.model: ctor &gt;__proto__: Object </code></pre> <p>These are the concrete table names from my (simple) database. If I expand "GameSet" then one of the properties is: defaultResourceName: "Sets" which is the navigation property name (defined in model as "Public Overridable Property Sets() As ICollection(Of GameSet)").</p> <p>Ah... just expanded "TeamerMVP" and its defaultresourcename is "TeamerMVPs" which is a small but subtle difference! I don't recall defining a version with the "s" on the end anywhere and a quick search of the project reveals no results. Curious. Maybe that's the issue, I'll have a quick play with the html bindings now. </p> <p>Edit 3: HTML Bindings info</p> <p>Nope, not playing ball at all... </p> <p>I have this template:</p> <pre><code> &lt;script type="text/html" id="TeamerMVPTemplate"&gt; &lt;div&gt;Teamer MVP(s):&amp;nbsp;&lt;/div&gt; &lt;li data-bind="text: Person().Name"&gt;&lt;/li&gt; &lt;/script&gt; </code></pre> <p>Which is embedded in another template (the main "foreach: games" one) which is where it is referenced: </p> <pre><code>&lt;span class="fixtureBoxLine" data-bind="template: { name: 'setScoresTemplate', foreach: Sets }"&gt;&lt;/span&gt; &lt;span class="fixtureBoxLine" data-bind="template: { name: 'TeamerMVPTemplate', foreach: TeamerMVPs }"&gt;&lt;/span&gt; </code></pre> <p>...and it just silently breaks. No error message but the processing stops on the first loop of the first game. The "foreach: Sets" template immediately above it works perfectly.</p> <p>If I change "foreach: TeamerMVPs" back to "foreach: TeamerMVP" in the binding declaration above, all games are processed but nothing is shown in the template for TeamerMVP so I guess "TeamerMVPs" is the correct entity reference and there's something odd going on with the way I'm trying to access it. Is "Person().Name" the correct binding in the template?</p> <p>===========================================</p> <p>Edit 4: Clarification of model</p> <p>manager.metadataStore.getEntityType('Game').navigationProperties returns 4 navigation properties. This is correct, there should be a collection of 0 to many "Sets", a collection of 0 to many "TeamerMVP", a 0 to one "MVP" and a 0 to one "Venue". All are present.</p> <p>There can be only one (or none) MVP but it is entirely correct for there to be 0 to many TeamerMVP. This relationship is set up in exactly the same way as the "Sets" relationship that works. The only slight difference being that the "TeamerMVP" tavle itself has a 1-to-1 relationship with the "Person" table as any TeamerMVP must be a valid person. This is why my breeze query defines an "expand" that refers to "TeamerMVP.Person" and this appears to work as the json data returned is exactly as I would expect. In the raw json, the navigation property is referred to as "TeamerMVP" and it is only in the "structuraltypemap" that the defaultResourceName is referred to as "TeamerMVPs".</p> <p>If I leave the html binding as "forEach TeamerMVP" then all games are returned and bound to the "foreach games" parent template as expected, but no data are bound to the TeamerMVP template and no errors are shown in the console. If I change the binding to "foreach TeamerMVPs" then only one game is returned and then processing stops at the point that the binding would occur and data would be shown. No error is show in the console, however.</p> <p>It appears as if breeze is creating the navigation property as "TeamerMVPs" internally and yet the json is returning "TeamerMVP" and maybe that disparity is why the binding appears to work and yet no data are bound? It's way above my comprehension at present!</p> <p>=================================================================</p> <p>Edit 5: Add model information</p> <p><strong>Game Model</strong></p> <pre><code>Public Class Game Public Property ID() As Integer Public Property GameDateTime() As System.DateTime Public Property Opponent() As String Public Property HomeGame() As Boolean Public Property LeagueGame() As Boolean Public Property MVP_PersonID() As Nullable(Of Integer) Public Property VenueID() As Nullable(Of Integer) Public Property isNL() As Boolean Public Overridable Property Sets() As ICollection(Of GameSet) Public Overridable Property MVP() As Person Public Overridable Property TeamerMVP() As ICollection(Of TeamerMVP) Public Overridable Property Venue() As Venue End Class </code></pre> <p><strong>TeamerMVP Model</strong></p> <pre><code>Public Class TeamerMVP Public Property GameID() As Integer Public Property PersonID() As Integer Public Overridable Property Person() As Person End Class </code></pre> <p><strong>Person Model</strong></p> <pre><code>Public Class Person Public Property ID() As Integer Public Property Name() As String Public Property isAdmin() As Boolean Public Property email() As String Public Property type() As String Public Property Image() As String Public Property thumbImage() As String Public Property backImage1() As String Public Property backImage2 As String Public Property Height() As String Public Property YearStarted() As String Public Property Position() As String Public Property PreviousClubs() As String Public Property ShirtNumber() As String Public Property isNL() As Boolean Public Overridable Property Games_MVP() As ICollection(Of Game) Public Overridable Property Games_TeamerMVP() As ICollection(Of Game) End Class </code></pre> <p><strong>GameSet Model</strong></p> <pre><code>Public Class GameSet Public Property ID() As Integer Public Property GameID() As Integer Public Property SetNo() As Integer Public Property ourScore() As Integer Public Property theirScore() As Integer Public Overridable Property Game() As Game End Class </code></pre> <p>Using <code>breezeConfig.manager.getEntities('TeamerMVP')</code> in the console at the success breakpoint does indeed reveal a whole load of "TeamerMVP" entities. The network resource tab shows the correct related entities for "TeamerMVP" in the raw returned data too.</p> <p>However, running <code>data.results[0].TeamerMVP()</code> in the console at the success breakpoint still returns nothing:</p> <pre><code>data.results[0].TeamerMVP() &gt;[] data.results[2].TeamerMVP() &gt;[] </code></pre> <p>The first one above is correct, the first returned game has no associated "TeamerMVP" entities as yet, but the 3rd game in the sequence does have associated entitities as shown in the raw json data returned:</p> <pre><code>TeamerMVP: [{$id:4, $type:lbD.model.TeamerMVP, lbD.model, GameID:24, PersonID:14,…},…] &gt;0: {$id:4, $type:lbD.model.TeamerMVP, lbD.model, GameID:24, PersonID:14,…} &gt;1: {$id:6, $type:lbD.model.TeamerMVP, lbD.model, GameID:24, PersonID:15,…} </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload