locked
Problem Deleting a Record in HTML5 Client RRS feed

  • Question

  • Hi

    I have the code below where I want to delete all records matching certain criteria.

    I call the function DeleteSurveys passing the results containing records to be deleted.

    How do I delete the actual records, 'cause my code is not doing what I expect.

    Many thanks in advance. Regards, Mark.

    // Starting a new audit
    
    myapp.ViewStoreGroup.btnAddStoreAudit_execute = function (screen) {
        if (screen.findContentItem("ResumeAudit").isVisible == true) {
            msls.showMessageBox("An incomplete survey is available to be resumed.", {
                title: "Are you sure you want to replace the existing audit?",
                buttons: msls.MessageBoxButtons.yesNo
            })
                .then(function (result) {
                    if (result === msls.MessageBoxResult.yes) {
                        screen.showTab("StoreDetail");
                        screen.details.displayName = screen.GroupList.selectedItem.Store.Name;
    
                        myapp.activeDataWorkspace.ApplicationData.SurveysCurrentStore()
                           .execute().then(function (results) {
                               var SurvRes = results;
                               DeleteSurveys(results, screen.GroupList.selectedItem.Store.Name);
                           });
                    }
                })
        }
        else {
            screen.showTab("StoreDetail");
            screen.details.displayName = screen.GroupList.selectedItem.Store.Name;
                return myapp.activeDataWorkspace.ApplicationData
         .saveChanges();
        }
    };
    
    // Check if there are existing "Started" surveys for the selected Store
    function CountSurveys(Surveys, StoreName) {
        var SurvTot = 0;
        var SurvRes = Surveys.results;
        SurvRes.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                SurvTot = SurvTot + 1;
        });
        return SurvTot;
    }
    
    // Delete "Started" surveys for the selected Store
    function DeleteSurveys(Surveys, StoreName) {
        var SurvRes = Surveys.results;
        SurvRes.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                // Delete the current survey
                survey.deleteSelected();
            myapp.applyChanges().then(null, function fail(e) {
                //If error
                msls.showMessageBox(e.message, { title: e.title }).then(function () {
                    //Discard changes
                    screen.details.dataWorkspace.ApplicationData
                    .details.discardChanges();
                })
            })
        });
    };


    Mark

    Tuesday, September 17, 2013 7:38 AM

Answers

  • A couple of things that seem odd to me:

    myapp.activeDataWorkspace.ApplicationData.Surveys_SingleOrDefault(survey.Id).execute()
        .then(function(duplicateSurvey) {
            duplicateSurvey.deleteEntity();
        })
    

    Why are you trying to execute a query to get the same exact instance of the entity that you already have? Replace this with just:

    survey.deleteEntity();

    Secondly, I don't think you need to call saveChanges on the data workspace and then call commitChanges on myapp. Call one or the other depending on which set of side effects you want.

    Lastly, you are probably running into a race condition between deleting entities and saving the changes. Using your code and debugging it, I've seen that more often than not, the save code is run before the delete code is run. What you need to do is take the promise that is returned by the execute method and then delete the entities and then from that promise, save the workspace:

    myapp.activeDataWorkspace.ApplicationData.Surveys.load().then(function (surveys) {
        surveys.results.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                survey.deleteEntity();
        });
    }).then(function (surveys) {
        myapp.commitChanges().then(null, function (e) {
            alert(e.message);
            myapp.cancelChanges();
            throw e;
        });
    });
    The above code is just an example, and is not exactly your code, but it demonstrates how to synchronize the call to commit the changes after all entities have been deleted.

    Justin Anderson, LightSwitch Development Team

    • Marked as answer by ITPSB Friday, September 20, 2013 5:43 AM
    Thursday, September 19, 2013 6:41 AM
    Moderator

All replies

  • It would be more helpful if you described a little more about what error you're getting or what behavior you're seeing with the code that isn't working. 

    Looking at your DeleteSurveys function, it seems you are trying to call a function meant to be used for the Visual Collection (.deleteSelected()) on a JavaScript array (Surveys.results).   Although it is true that JavaScript arrays are passed by value, manipulating this array by deleting, adding, sorting, etc., will not affect the Visual Collection object.

    So, once you've identified a candidate survey for deletion, you could use the Id of that survey to retrieve the visual collection entity and then delete it, like this:

    function DeleteSurveys(Surveys, StoreName) {
        var SurvRes = Surveys.results;
        SurvRes.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                // Delete the current survey
               myapp.activeDataWorkspace.ApplicationData.Surveys_SingleOrDefault(survey.Id).execute()
                   .then(function(duplicateSurvey) {
                              duplicateSurvery.deleteEntity();
                         }
    ...


    Tuesday, September 17, 2013 2:39 PM
  • Hi Allen

    Many thanks for your assistance.

    What I am trying to achieve is as follows:

    (1) If the user logs-off from the app leaving behind one or more incomplete store audit records,(should only be one but I'm allowing for situations where for whatever reason there's more than one)

    (2) And on logging back in, the user wants to start a new store audit for a store that has existing incomplete store audits, then I want to warn the user that incomplete audits for the same store exist and that

    (3) Creating a new audit will cause the existing incomplete store audits to be deleted before a new store audit is created.

    (4) If the user confirms they want the incomplete store audits purged and a new store audit created then I have the following code (updated as best I could with your code suggestion).

    But I find that the new store audit has indeed been created but the incomplete store audit records are not deleted by the following code.

    Your assistance is greatly appreciated. Thanks.

    // Delete "Started" surveys for the selected Store
    function DeleteSurveys(Surveys, StoreName) {
        var SurvRes = Surveys.results;
        SurvRes.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                // Delete the current survey
                myapp.activeDataWorkspace.ApplicationData.Surveys_SingleOrDefault(survey.Id).execute()
                    .then(function(duplicateSurvey) {
                        duplicateSurvery.deleteEntity();
                    })
            });
            myapp.activeDataWorkspace
            .ApplicationData.saveChanges().then(function () {
                return myapp.commitChanges().then(null, function fail(e) {
                    alert(e.message);
                    myapp.cancelChanges();
                    throw e;
            });
        })
    }

    Mark

    Wednesday, September 18, 2013 6:06 AM
  • When you set a breakpoint and run the application in debug mode, does it get to the line:

    duplicateSurvery.deleteEntity();
    


    Unleash the Power - Get the LightSwitch HTML Client book

    http://LightSwitchHelpWebsite.com

    Wednesday, September 18, 2013 1:07 PM
  • When you set a breakpoint and run the application in debug mode, does it get to the line:

    duplicateSurvery.deleteEntity();


    Hi Michael

    Yes it does. I tested and it hit the break-point 3 times then created the new record and now I have 4 records (see below).

    Thanks for assisting.


    Mark

    Thursday, September 19, 2013 12:51 AM
  • Please correct the inadvertent spelling error:

    duplicateSurvey.deleteEntity();

    Thursday, September 19, 2013 1:04 AM
  • Hi

    I corrected the typo but the records still do not get deleted.

    The corrected code is below.

    Thanks for assisting.

    // Delete "Started" surveys for the selected Store
    function DeleteSurveys(Surveys, StoreName) {
        var SurvRes = Surveys.results;
        SurvRes.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                // Delete the current survey
                myapp.activeDataWorkspace.ApplicationData.Surveys_SingleOrDefault(survey.Id).execute()
                    .then(function(duplicateSurvey) {
                        duplicateSurvey.deleteEntity();
                    })
            });
            myapp.activeDataWorkspace
            .ApplicationData.saveChanges().then(function () {
                return myapp.commitChanges().then(null, function fail(e) {
                    alert(e.message);
                    myapp.cancelChanges();
                    throw e;
            });
        })
    }


    Mark

    Thursday, September 19, 2013 2:40 AM
  • Last but not least...

    I am assuming that when the breakpoint on duplicateSurvey.deleteEntity() was hit that you were able to inspect the duplicateSurvey object to confirm that it is the entity you want deleted.  In order to immediately persist the deletion in the database, you will need to follow that line with:

    myapp.commitChanges();

    Otherwise, the user will be prompted to save the changes before the screen closes.

    Thursday, September 19, 2013 2:54 AM
  • Hi Allen

    In the image below are 2 screenshots of what I see when debugging. Also I have a myapp.commitChange(); statement (see highlight below). I wanted to do it once all the changes were made. Am I doing it incorrectly? Should it be after each delete?

    Many thanks.


    Mark

    Thursday, September 19, 2013 5:19 AM
  • Well, I learned 2 new things from trying to help with this thread:

    (1) The query _SingleOrDefault() returns an array itself of results, even though I had expected it to return only a single entity.

    (2) The LS API does allow you to operate on the query array results, so that this code actually works, despite what I had asserted earlier:

    duplicateSurvey.results[0].deleteEntity();

    I know this because I was able to test it out myself.  Which then leads back to the question of why your original code did not work.  I can't test out that scenario because I don't have a similar project, but I wonder if instead of

    survey.deleteSelected();

    you had

    survey.deleteEntity();

    if it would have worked originally.

    Finally, it would seem better to have the changes committed at the conclusion of the loop after all the changes had been made to cut down on the number of round trips to the server, as you have in the code above.

    Thursday, September 19, 2013 6:17 AM
  • A couple of things that seem odd to me:

    myapp.activeDataWorkspace.ApplicationData.Surveys_SingleOrDefault(survey.Id).execute()
        .then(function(duplicateSurvey) {
            duplicateSurvey.deleteEntity();
        })
    

    Why are you trying to execute a query to get the same exact instance of the entity that you already have? Replace this with just:

    survey.deleteEntity();

    Secondly, I don't think you need to call saveChanges on the data workspace and then call commitChanges on myapp. Call one or the other depending on which set of side effects you want.

    Lastly, you are probably running into a race condition between deleting entities and saving the changes. Using your code and debugging it, I've seen that more often than not, the save code is run before the delete code is run. What you need to do is take the promise that is returned by the execute method and then delete the entities and then from that promise, save the workspace:

    myapp.activeDataWorkspace.ApplicationData.Surveys.load().then(function (surveys) {
        surveys.results.forEach(function (survey) {
            if (survey.StoreName == StoreName && survey.Status == "Started")
                survey.deleteEntity();
        });
    }).then(function (surveys) {
        myapp.commitChanges().then(null, function (e) {
            alert(e.message);
            myapp.cancelChanges();
            throw e;
        });
    });
    The above code is just an example, and is not exactly your code, but it demonstrates how to synchronize the call to commit the changes after all entities have been deleted.

    Justin Anderson, LightSwitch Development Team

    • Marked as answer by ITPSB Friday, September 20, 2013 5:43 AM
    Thursday, September 19, 2013 6:41 AM
    Moderator
  • Hi Justin

    Many thanks indeed.

    I'll study your responses, apply your suggestions then update this topic once I've done that.

    Best.


    Mark

    Thursday, September 19, 2013 9:21 AM
  • Well, I learned 2 new things from trying to help with this thread:

    (1) The query _SingleOrDefault() returns an array itself of results, even though I had expected it to return only a single entity.

    (2) The LS API does allow you to operate on the query array results, so that this code actually works, despite what I had asserted earlier:

    duplicateSurvey.results[0].deleteEntity();

    I know this because I was able to test it out myself.  Which then leads back to the question of why your original code did not work.  I can't test out that scenario because I don't have a similar project, but I wonder if instead of

    survey.deleteSelected();

    you had

    survey.deleteEntity();

    if it would have worked originally.

    Finally, it would seem better to have the changes committed at the conclusion of the loop after all the changes had been made to cut down on the number of round trips to the server, as you have in the code above.

    Hi Allen

    Many thanks for your assistance. I too am learning (but not quite as fast as I'd like to ;-)

    I'll update the topic once I've had time to study and apply all the suggestions.

    I very much appreciate your support. Best.


    Mark

    Thursday, September 19, 2013 9:24 AM
  • A couple of things that seem odd to me:

    myapp.activeDataWorkspace.ApplicationData.Surveys_SingleOrDefault(survey.Id).execute()
        .then(function(duplicateSurvey) {
            duplicateSurvey.deleteEntity();
        })

    Why are you trying to execute a query to get the same exact instance of the entity that you already have?


    He's doing that because I had incorrectly told him he needed to.  But catching and fessing up to that error should hopefully set that straight.
    Thursday, September 19, 2013 3:09 PM
  • Hi Justin and Allen

    Thank you very much for your assistance.

    Justin's code worked straight away! WHoo Hooo :-)

    Just for the record, this is the code that worked in my specific project.

    Many thanks indeed!

    // Delete "Started" surveys for the selected Store
    
    function DeleteSurveys(Surveys, StoreName) {
        var SurvRes = Surveys.results;
        myapp.activeDataWorkspace.ApplicationData.Surveys.load().then(function (surveys) {
            surveys.results.forEach(function (survey) {
                if (survey.StoreName == StoreName && survey.Status == "Started")
                    survey.deleteEntity();
            });
        }).then(function (surveys) {
            myapp.commitChanges().then(null, function (e) {
                alert(e.message);
                myapp.cancelChanges();
                throw e;
            });
        });
    }


    Mark

    Friday, September 20, 2013 5:43 AM