locked
Sorting in a "foreach" statement RRS feed

  • Question

  • Hi

    I have a table that is sorted (as shown below). The table is used as a 'temporary' data table for the ExcelImporter.

    I assumed (incorrectly) that by having the table sorted when I use this statement:

    foreach (ChainsTemp Ct in ChainsTemps) // Loop through import chains

    I would be able to iterate through a sorted list. However the records are in the order that they were in the imported Excel file.

    How can I sort the data so that it's in ascending order?

    Many thanks, Mark.


    Mark

    Friday, February 7, 2014 9:59 AM

Answers

  • Do a ChainsTemp.OrderBy(... or create a custom query against the ChainsTemp entity and use that as the screen property instead.

    Dave Baker | AIDE for LightSwitch | Xpert360 blog | twitter : @xpert360 | Xpert360 website | Opinions are my own. For better forums, remember to mark posts as helpful/answer.

    • Marked as answer by ITPSB Saturday, February 8, 2014 3:29 AM
    Friday, February 7, 2014 11:01 AM
  • Let me give a little background on why you see that these entities are not sorted.

    All queries in LightSwitch are executed at the data source. So when you define a query in the designer or write one in code using the IDataServiceQueryable interface, all of them are serialized to the server (if they already aren't on the server), the server translates the queries into what the data providers understand, and they are executed at the data source.

    The entities that you have imported temporarily (and the key is that these are newly added entities) are newly added and only exist on the client. When adding them to particular visual collections, LightSwitch does not filter or sort these entities in any manner. They are just added to the end of the visual collection. The reason is that for the sorting or filtering to work, these entities would need to somehow be serialized to the data source, where the queries are executed, in order to determine where they should be placed if they match the filter criteria at all and the entire result set would need to be returned to the server and client and merged back with what the client already has. It's kind of complicated and heavy just to make sure unsaved entities are filtered and sorted.

    The LightSwitch runtime does not have any support for performing filtering and sorting local to the tier in which the code is running. This is what you would need in order to get the proper filtering and sorting that you'd expect, but it just doesn't exist.

    Once the entities are saved (and you refresh the visual collection), they will then respect the filter and sort conditions as specified by the involved queries.

    You can use Dave's suggestion to replicate your query's sorting and filtering on the client tier so that newly added entities respect the ordering that you want, which is probably the easiest way to do this with newly added entities.


    Justin Anderson, LightSwitch Development Team

    • Marked as answer by ITPSB Saturday, February 8, 2014 3:29 AM
    Friday, February 7, 2014 8:16 PM
    Moderator
  • This works for me:

            partial void ChainsModify_Execute()
            {
                var sb = new StringBuilder();
                foreach (var temp in ChainsTemps.OrderBy(o => o.Name))
                {
                    sb.AppendLine(temp.Name);
                }
                Msg = sb.ToString();
            }
    

    I think the OrderBy syntax you used did not sort by name and was looking for default sort handler.

    Dave


    Dave Baker | AIDE for LightSwitch | Xpert360 blog | twitter : @xpert360 | Xpert360 website | Opinions are my own. For better forums, remember to mark posts as helpful/answer.

    • Marked as answer by ITPSB Sunday, February 9, 2014 4:55 AM
    Saturday, February 8, 2014 11:35 AM

All replies

  • Do a ChainsTemp.OrderBy(... or create a custom query against the ChainsTemp entity and use that as the screen property instead.

    Dave Baker | AIDE for LightSwitch | Xpert360 blog | twitter : @xpert360 | Xpert360 website | Opinions are my own. For better forums, remember to mark posts as helpful/answer.

    • Marked as answer by ITPSB Saturday, February 8, 2014 3:29 AM
    Friday, February 7, 2014 11:01 AM
  • Let me give a little background on why you see that these entities are not sorted.

    All queries in LightSwitch are executed at the data source. So when you define a query in the designer or write one in code using the IDataServiceQueryable interface, all of them are serialized to the server (if they already aren't on the server), the server translates the queries into what the data providers understand, and they are executed at the data source.

    The entities that you have imported temporarily (and the key is that these are newly added entities) are newly added and only exist on the client. When adding them to particular visual collections, LightSwitch does not filter or sort these entities in any manner. They are just added to the end of the visual collection. The reason is that for the sorting or filtering to work, these entities would need to somehow be serialized to the data source, where the queries are executed, in order to determine where they should be placed if they match the filter criteria at all and the entire result set would need to be returned to the server and client and merged back with what the client already has. It's kind of complicated and heavy just to make sure unsaved entities are filtered and sorted.

    The LightSwitch runtime does not have any support for performing filtering and sorting local to the tier in which the code is running. This is what you would need in order to get the proper filtering and sorting that you'd expect, but it just doesn't exist.

    Once the entities are saved (and you refresh the visual collection), they will then respect the filter and sort conditions as specified by the involved queries.

    You can use Dave's suggestion to replicate your query's sorting and filtering on the client tier so that newly added entities respect the ordering that you want, which is probably the easiest way to do this with newly added entities.


    Justin Anderson, LightSwitch Development Team

    • Marked as answer by ITPSB Saturday, February 8, 2014 3:29 AM
    Friday, February 7, 2014 8:16 PM
    Moderator
  • That is excellent background info.

    Friday, February 7, 2014 9:09 PM
  • Wow!

    Great explanation Justin and thanks again Dave. Your assistance is very much appreciated.

    Below are the two lines of code I added to sort the data :-)

    Many many thanks, Mark.

    partial void ImportChains_Execute() // User clicks the Import button { ExcelImporter.Importer.ImportFromExcel(ChainsTemps); // Import to temporary file             this.DataWorkspace.ApplicationData.SaveChanges(); // Save the data

    this.FindControl("ChainsTempData").IsVisible = true; this.FindControl("ChainsRow").IsVisible = false; this.FindControl("ChainDetails").IsVisible = false; } partial void ChainsModify_Execute() // User can modify (fine-tune) the imported data and when done clicks a button to proceed { ChainsTemps.Refresh(); // Following Dave and Justin's advice, this refreshes the visual collection whereafter the data are sorted ;-) Whoopie!! this.FindControl("ChainsTempData").IsVisible = false; this.FindControl("ChainsRow").IsVisible = true; this.FindControl("ChainDetails").IsVisible = true;



    Mark



    • Edited by ITPSB Saturday, February 8, 2014 4:30 AM typo
    Saturday, February 8, 2014 3:37 AM
  • Hi

    This is getting a bit weird :/

    I swear the above worked when I tested but it seems to go wrong most of the time now.

    So I tried Dave's suggestion but am a bit stuck again.

    When I try the code below I get a red squigglie under "OrderBy" and the error reads "LightswitchApplication.ChainsTemp does not contain a definition for OrderBy".

    I do have a using System.Linq;

            partial void ImportChains_Execute()
            {
                ExcelImporter.Importer.ImportFromExcel(ChainsTemps);
                this.DataWorkspace.ApplicationData.SaveChanges();
                this.FindControl("ChainsTempData").IsVisible = true;
                this.FindControl("ChainsRow").IsVisible = false;
                this.FindControl("ChainDetails").IsVisible = false;
            }
    
            partial void ChainsModify_Execute()
            {
                this.ChainsTemps.Refresh();
                IEnumerable<ChainsTemp> query = ChainsTemp.OrderBy(Name => Name);
                this.FindControl("ChainsTempData").IsVisible = false;
                this.FindControl("ChainsRow").IsVisible = true;
                this.FindControl("ChainDetails").IsVisible = true;

    Can you please assist (again).

    Thanks, Mark.


    Mark

    Saturday, February 8, 2014 6:42 AM
  • This works for me:

            partial void ChainsModify_Execute()
            {
                var sb = new StringBuilder();
                foreach (var temp in ChainsTemps.OrderBy(o => o.Name))
                {
                    sb.AppendLine(temp.Name);
                }
                Msg = sb.ToString();
            }
    

    I think the OrderBy syntax you used did not sort by name and was looking for default sort handler.

    Dave


    Dave Baker | AIDE for LightSwitch | Xpert360 blog | twitter : @xpert360 | Xpert360 website | Opinions are my own. For better forums, remember to mark posts as helpful/answer.

    • Marked as answer by ITPSB Sunday, February 9, 2014 4:55 AM
    Saturday, February 8, 2014 11:35 AM
  • Hi Dave and many thanks yet again.

    I changed mine to your code (changing the "temp" to "Ct" to suit my code) and added the namespace:

    using System.Text;

    And Viola ! It worked like a charm!

    Many thanks for assistance.


    Mark

    Sunday, February 9, 2014 4:55 AM
  • Did you try returning an IQueryable instead of an IEnumerable?
    Sunday, February 9, 2014 5:40 AM
  • Hi

    Thanks for your suggestion.

    Dave's solution worked so I'll leave it as it is with IEnumerable.

    Thanks, Mark.


    Mark

    Sunday, February 9, 2014 8:30 AM