Results 1 to 3 of 3

Thread: Issue with getAssociatedD on a Model having multiple hasMany associations

    Wait! Looks like we don't have enough information to add this to bug database. Please follow this template bug format.
  1. #1
    Sencha Premium Member
    Join Date
    Oct 2011
    Location
    Duluth, MN
    Posts
    151

    Default Issue with getAssociatedD on a Model having multiple hasMany associations

    Hi guys,<br>
    <br>
    <u><strong><font color="green">REQUIRED INFORMATION</font></strong></u><br>
    <br>
    <br>
    <br>
    <br>
    <strong><u>Ext version tested:</u></strong><ul><li>Touch 2.1, and 2.1 with 2.2 function (I copied the 2.2 function to the 2.1 code to see if the small changes in the prepareAssociatedData fixed this specific issue. It did not fix the issue.)</li></ul><br>
    <strong><u>Browser versions tested against:</u></strong><ul><li>Chrome</li></ul><br>
    <strong><u>DOCTYPE tested against:</u></strong><ul><li>____</li></ul><br>
    <strong><u>Description:</u></strong><ul><li><br>
    I started out trying to fix a problem with 2.1 in the prepareAssociatedData function where only one hasmany association would get any data returned and that association would only have 1 record in the resulting array. When checking the 2.2. code I noticed that there was a change that may take care of the problem. The change fixed the issue with only one record being returned, however the other hasmany associations remained empty. What happens is the prepareAssociatedData function doesn't work properly when you have more than one hasmany associations each of which has a model with a backreferenced belongsTo association. What seems to happen is only one of the hasmany associations will be retrieved with data. <br>
    <br>
    <br>
    So if you have a model <br>
    Person <br>
    HasMany: PhoneNumbers<br>
    HasMany: Messages<br>
    HasMany: Children<br>
    <br>
    and <br>
    PhoneNumber, Message, and Child all have a BelongsTo reference back to the Person called Person, when you do Person.getAssociatedData() you will have only one of the hasMany arrays filled in. <br>
    <br>
    <br>
    So if your person has 2 phone numbers, 3 messages, and 2 children, you would wind up with a returned object looking something like this. <br>
    <br>
    <br>
    {<br>
    PhoneNumbers:[],<br>
    Messages:[],<br>
    Children:[<br>
    {<br>
    childId:1,<br>
    Person:{personId:1....}<br>
    },<br>
    {<br>
    childId:2,<br>
    Person:{personId:1....}<br>
    }<br>
    ]<br>
    }</li></ul><br>
    <strong><u>The result that was expected:</u></strong><ul><li>All associations with data would be represented with their data.</li></ul><br>
    <strong><u>The result that occurs instead:</u></strong><ul><li>Only one association would have it's data copied to the resulting object.</li></ul><br>
    <strong><u>Test Case:</u></strong><br>
    <br>
    <br>
    Code:
    <br>
    &nbsp;&nbsp; &nbsp;&lt;&lt;insert working code to reproduce the report &gt;&gt;<br>
    <br>
    <br>
    <br>
    <br>
    <br>
    <br>
    <br>
    <u><strong><font color="green">HELPFUL INFORMATION</font></strong></u><br>
    <br>
    <br>
    <br>
    <br>
    <strong><u>Screenshot or Video:</u></strong><ul><li>attached</li></ul><br>
    <strong>See this URL for live test case:</strong> http://<br>
    <br>
    <br>
    <br>
    <br>
    <strong><u>Debugging already done:</u></strong><ul><li>none</li></ul><br>
    <strong><u>Possible fix:</u></strong><ul><li>Here's an override that fixes this. It works in 2.1 for sure and probably works in 2.2. This works for my particular scenario but unsure/untested how it will work for a more general belongsto scenario. I don't think the associated data will be included in the reference to the parent that is returned. <br>
    <br>
    <br>
    Code:
    Ext.define('Ext.fixes.data.FixGetAssociationData', {<br>
        override:'Ext.data.Model',<br>
    <br>
    <br>
    //override change.  Added another parameter to track the parent record for the record being processed. <br>
        prepareAssociatedData: function(record, ids, associationType, parent) {<br>
            //we keep track of all of the internalIds of the models that we have loaded so far in here<br>
            var associations     = record.associations.items,<br>
                associationCount = associations.length,<br>
                associationData  = {},<br>
                recursiveAssociationQueue = [],<br>
                associatedStore, associationName, associatedRecords, associatedRecord,<br>
                associatedRecordCount, association, id, i, j, type, allow, recursiveAssociationItem;<br>
    <br>
    <br>
            for (i = 0; i &lt; associationCount; i++) {<br>
                association = associations[i];<br>
                associationName = association.getName();<br>
                type = association.getType();<br>
                allow = true;<br>
    <br>
    <br>
                if (associationType) {<br>
                    allow = type == associationType;<br>
                }<br>
    <br>
    <br>
                if (allow &amp;&amp; type.toLowerCase() == 'hasmany') {<br>
                    //this is the hasMany store filled with the associated data<br>
                    associatedStore = record[association.getStoreName()];<br>
    <br>
    <br>
                    //we will use this to contain each associated record's data<br>
                    associationData[associationName] = [];<br>
    <br>
    <br>
                    //if it's loaded, put it into the association data<br>
                    if (associatedStore &amp;&amp; associatedStore.getCount() &gt; 0) {<br>
                        associatedRecords = associatedStore.data.items;<br>
                        associatedRecordCount = associatedRecords.length;<br>
    <br>
    <br>
                        recursiveAssociationQueue.length = 0;<br>
                        //now we're finally iterating over the records in the association. We do this recursively<br>
                        for (j = 0; j &lt; associatedRecordCount; j++) {<br>
                            associatedRecord = associatedRecords[j];<br>
                            // Use the id, since it is prefixed with the model name, guaranteed to be unique<br>
                            id = associatedRecord.id;<br>
    <br>
    <br>
                            //when we load the associations for a specific model instance we add it to the set of loaded ids so that<br>
                            //we don't load it twice. If we don't do this, we can fall into endless recursive loading failures.<br>
                            if (Ext.Array.indexOf(ids, id) == -1) {<br>
                                ids.push(id);<br>
    <br>
    <br>
                                associationData[associationName][j] = associatedRecord.getData();<br>
                                recursiveAssociationQueue.push({<br>
                                    associationName:associationName,<br>
                                    j:j,<br>
                                    associatedRecord:associatedRecord,<br>
                                    ids:ids,<br>
                                    associationType:associationType<br>
                                });<br>
                            }<br>
                        }<br>
    <br>
    <br>
                        while (recursiveAssociationQueue.length &gt; 0) {<br>
                            recursiveAssociationItem = recursiveAssociationQueue.shift();<br>
    //OVERRIDE CHANGE:  Added parent record to be passed to the recursive call to prepareAssociatedData<br>
                            Ext.apply(associationData[recursiveAssociationItem.associationName][recursiveAssociationItem.j], this.prepareAssociatedData(recursiveAssociationItem.associatedRecord, recursiveAssociationItem.ids, recursiveAssociationItem.associationType, record));<br>
                        }<br>
                    }<br>
                } else if (allow &amp;&amp; (type.toLowerCase() == 'belongsto' || type.toLowerCase() == 'hasone')) {<br>
                    associatedRecord = record[association.getInstanceName()];<br>
                    if (associatedRecord !== undefined ) {<br>
                        id = associatedRecord.id;<br>
                        if (Ext.Array.indexOf(ids, id) === -1) {<br>
                            ids.push(id);<br>
                            associationData[associationName] = associatedRecord.getData();<br>
    //OVERRIDE CHANGE - check to see if the belongsto record is the "parent" of the record you are processing, if it is don't load the associatedData.  Also when we call the associationData record we will pass the record as the parent. <br>
                            if (!parent || associatedRecord != parent){<br>
                                Ext.apply(associationData[associationName], this.prepareAssociatedData(associatedRecord, ids, associationType, record));<br>
                            }<br>
                        }<br>
                    }<br>
                }<br>
            }<br>
    <br>
    <br>
            return associationData;<br>
        }<br>
    });
    </li></ul><br>
    <strong><u>Additional CSS used:</u></strong><ul><li>only default ext-all.css</li><li>custom css (include details)</li></ul><br>
    <strong><u>Operating System:</u></strong><ul><li>________</li><li>WinXP Pro</li></ul>

  2. #2
    Sencha Premium User mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    40,379

    Default

    Can I get a working test case that I can run locally to see the issue? Also, when posting code, please use BBCode CODE tags.
    Mitchell Simoens @LikelyMitch

    Check out my GitHub:
    https://github.com/mitchellsimoens

    Posts are my own, not any current, past or future employer's.

  3. #3
    Sencha Premium Member
    Join Date
    Oct 2011
    Location
    Duluth, MN
    Posts
    151

    Default

    I'll try to put something together this week.

    I tried to add the code tags and the editor reformatted everything by escaping the html tags for some reason. I don't have time right now to rebuild the post unfortunately, sorry bout that.

    Thanks
    Bob

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •