0

I am trying to load an entity based on a Query and allow the user to edit it. The entity loads without issues from the query, however it does not load its related entities, leaving detail pickers unfilled when loading the edit screen.

This is the code that I have:

    myapp.BrowseCOAMissingHoldingCompanies.VW_ChartOfAccountsWithMissingHoldingCompanies_ItemTap_execute = function (screen) {
         var accountName = screen.VW_ChartOfAccountsWithMissingHoldingCompanies.selectedItem.AccountFullName;
        return myapp.activeDataWorkspace.Accounting360Data.FindChartOfAccountsMappingByAccountName(accountName)
          .execute().then(function (query) {
            var coa = query.results[0];
            return myapp.showAddEditChartOfAccountsMapping(coa, {
                beforeShown: function (addEditScreen) {
                    addEditScreen.ChartOfAccountsMapping = coa;

                },
                afterClosed: function () {
                    screen.VW_ChartOfAccountsWithMissingHoldingCompanies.refresh();
                }
            });
    });
};

Interestingly if I open the browse screen (and nothing else) of that entity type first (which does retrieve the entity), then the related entities load correctly and everything works, but I can't figure out how to make that level of load happen in this code.

Yishai
  • 90,445
  • 31
  • 189
  • 263
  • Do you have access to the definition of `FindChartOfAccountsMappingByAccountName`? – Isaac Kleinman Mar 08 '16 at 17:37
  • In lightswitch all you can get on that is a screen shot, unfortunately. It doesn't do anything interesting other than accept the one parameter and return a single result. – Yishai Mar 08 '16 at 17:53

4 Answers4

1

One method of tackling this (and to avoid the extra query execution of a follow on refresh) is to use the expand method to include any additional navigation properties as follows:

myapp.BrowseCOAMissingHoldingCompanies.VW_ChartOfAccountsWithMissingHoldingCompanies_ItemTap_execute = function (screen) {
    var accountName = screen.VW_ChartOfAccountsWithMissingHoldingCompanies.selectedItem.AccountFullName;
    return myapp.activeDataWorkspace.Accounting360Data.FindChartOfAccountsMappingByAccountName(
        accountName
    ).expand(
        "RelatedEntity," +
        "AnotherRelatedEntity," +
        "AnotherRelatedEntity/SubEntity"
    ).execute().then(function (query) {
        var coa = query.results[0];
        return myapp.showAddEditChartOfAccountsMapping(coa, {
            beforeShown: function (addEditScreen) {
                addEditScreen.ChartOfAccountsMapping = coa;
            },
            afterClosed: function () {
                screen.VW_ChartOfAccountsWithMissingHoldingCompanies.refresh();
            }
        });
    });
}

As you've not mentioned the name of your entity's navigational properties, I've used coa.RelatedEntity, coa.AnotherRelatedEntity and coa.AnotherRelatedEntity.SubEntity in the above example.

As covered by LightSwitch's intellisense (in msls-?.?.?-vsdoc.js) this method 'Expands results by including additional navigation properties using an expression defined by the OData $expand system query option' and it accepts a single parameter of 'An OData expand expression (a comma-separated list of names of navigation properties)'.

The reason your forced refresh of coa also populates the navigational properties is that LightSwitch's refresh method implicitly expands all navigation properties (provided you don't specify the navigationPropertyNames parameter when calling the refresh). The following shows the internal implementation of the LightSwitch refresh method (with the implicit expand behaviour executing if the navigationPropertyNames parameter is null):

function refresh(navigationPropertyNames) {

    var details = this,
        properties = details.properties.all(),
        i, l = properties.length,
        property,
        propertyEntry,
        query;

    if (details.entityState !== _EntityState.unchanged) {
        return WinJS.Promise.as();
    }

    if (!navigationPropertyNames) {
        navigationPropertyNames = [];
        for (i = 0; i < l; i++) {
            property = properties[i];
            propertyEntry = property._entry;
            if (isReferenceNavigationProperty(propertyEntry) &&
                !isVirtualNavigationProperty(propertyEntry)) {
                navigationPropertyNames.push(propertyEntry.serviceName);
            }
        }
    }

    query = new _DataServiceQuery(
        {
            _entitySet: details.entitySet
        },
        details._.__metadata.uri);
    if (navigationPropertyNames.length > 0) {
        query = query.expand(navigationPropertyNames.join(","));
    }

    return query.merge(msls.MergeOption.unchangedOnly).execute();
}

However, if you take the refresh approach, you'll be performing an additional unnecessary query operation.

Chris Cook
  • 2,821
  • 1
  • 20
  • 32
0

Entity Framework uses lazy loading by default, so related data will be loaded on demand, but in your case that's too late because the entity is already client-side a that point.

Try using the Include method in your query if you want eager loading.

Isaac Kleinman
  • 3,994
  • 3
  • 31
  • 35
  • Thanks, unfortunately in Lightswitch you don't have control over how it calls the entity framework. – Yishai Mar 08 '16 at 17:54
0

Calling refresh on the details of the entity seems to do it:

        return coa.details.refresh().then(function() {
            return myapp.showAddEditChartOfAccountsMapping(coa, {
                beforeShown: function (addEditScreen) {
                    addEditScreen.ChartOfAccountsMapping = coa;

                },
                afterClosed: function () {
                    screen.VW_ChartOfAccountsWithMissingHoldingCompanies.refresh();
                }
            });
        });
Yishai
  • 90,445
  • 31
  • 189
  • 263
0

You should use load method to fetch related data from Server. At this time we don't have any ways to force msls load related data.

Linh
  • 1,024
  • 2
  • 16
  • 28