none
DBContext.Savechanges query RRS feed

  • Question

  • This really has me stumped. Obviously I've misunderstood something or a vital piece of info hasn't quite sunk in. I'm new to EF having come in at 4.3 with code first. I have a form that instantiates a DBContext object. I have some databound winforms controls and also a public method that calls the DBContext.SaveChanges (called SaveEntity). If I change a field value and call SaveEntity from inside the form (e.g. in response to a button press) it saves the value fine. However if I call the SaveEntity public method from another form (e.g. the parent form that instantiated the one above) no update occurs. I've added some debug lines to read the status of the changetracker entity's current values and they still hold the original values, not the ones I've just updated. So next I created a property in the child form, and when that value is set I called SaveEntity (thinking that now it will be called locally and all will be well right? - well no, it wasn't). Am I missing something here?
    Monday, July 9, 2012 4:21 PM

Answers

  • I've just had a eureka moment. It's caused by the fact that when you click a toolstrip button, the textbox in which you changed the value does not lose focus, therefore the edit in effect hasn't finished yet. This explains why the normal button works, because as soon as you click it, the button takes focus from the textbox.

    So, is there an "approved" method of dealing with this, or can I just be sneaky and change focus to a textbox on the parent form which is outside the visible area whrn you click a toolbar (which works).


    Gavin Williams

    Tuesday, July 10, 2012 1:58 PM

All replies

  • Hi,

    How many context(s) do you have ? From your description my current understanding is that you have a context in the child form and another one in the parent form ? Or do you have a single context ?

    When  calling SaveChanges against a context, only entities tracked by this particular context are dealt with...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    Monday, July 9, 2012 4:49 PM
  • Are you using the same DBContext or different contexts?  Using different contexts will have the weird behaviour you describe.
    Monday, July 9, 2012 5:00 PM
  • I have just the one context that was created inside my child form.  
    Tuesday, July 10, 2012 7:27 AM
  • 100% sure ? Your debug code is before saving ? If you see no changes, it is expected that SaveChanges won't do anything. For now it seems to me that for some reason, the context you are using doesn't know anything about the changes.

    The location from which a method is called doesn't matter at all. So more likely you are not calling the same method but perhaps one that belongs to another object.

    A known approach is to create a very small test project just to test your architecute and show the issue. Usually you'll find it works and what differs from the real code. Else you'll have the minimal amount of code to show to others so that they can possibly understand what is going wrong with your approach.

    BTW how do you call it from your parent form ?


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    Tuesday, July 10, 2012 8:52 AM
  • OK, I have a form (frmMain) which is an MDI container. It has a toolbar which contains a button that, when clicked creates my child form and set its mdiparent to frmMain. 

    My child form has a private variable for the dbcontext, which is instantiated in the child form constructor. My child form contains a button that when clicked calls a method (which also resides in the child form but is public) called SaveEntity. This contains the context.Savechanges call.

    This works fine. I can make changes to the databound fields, click the button to save and all is good in the db.

    If I create a toolbar button on frmMain that when clicked casts and calls ActiveMdiChild.SaveEntity it doesn't save the changes, because for whatever reason it thinks the data hasn't changed. Interestingly I have just put a normal button on frmMain, cast and called ActiveMdiChild.SaveEntity and that works! So then I tried the same from a menu item to see whether it was just an issue with toolbars and that doesn't work either!

    So if I place a button on the parent form and call my public SaveEntity method on the child form it works, but if I try the same from a toolbar or menu item it doesn't. Is there some kind if UI threading thing going on here?


    Gavin Williams

    Tuesday, July 10, 2012 10:40 AM
  • Weird. You could try System.Threading.Thread.Current.ManagedThreadId but I doubt this is the issue.

    I really don't see why it would run from a button but not when triggered from any other UI element. As the change seems to be unvisible then, it seems really that either the  change is not triggered yet (but once again why would you have a different result in both cases) or that (and this is about the only thing I can think off) that either you don't address the same data (that would explain why changes are not visible) or perhaps that somewhere else you reload the source data (when the menu is activated or whatever ?)

    I would really just try a bare bone project with just that. Either you'll repro the issue or you'll see it works as expected and then you'll have to find out which differences are left. What is the call you have in the context menu compared with the button ?

    For example one of my thought if using VB would be a default form instance issue...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".


    Tuesday, July 10, 2012 10:52 AM
  • These are the event handlers for the various UI elements in frmMain. My child forms inherit from FormBase and override its SaveEntity method.

            private void toolStripButtonSave_Click(object sender, EventArgs e)
            {
                ((FormBase)ActiveMdiChild).SaveEntity(); // doesn't work
            }

            private void saveToolStripMenuItem_Click(object sender, EventArgs e)
            {
                ((FormBase)ActiveMdiChild).SaveEntity(); // doesn't work
            }

            private void button1_Click(object sender, EventArgs e)
            {
                ((FormBase)ActiveMdiChild).SaveEntity(); // works
            }

    Thanks for your patience. Like you say I'll have to create a bare bones project and see if I can reproduce the issue.


    Gavin Williams

    Tuesday, July 10, 2012 11:01 AM
  • Looks really surprising. You could start by a button on a child form that triggers a change and a UI on the parent form that call SaveChanges...

    You tried to follow the control flow step by step using the debugger ? Handlers are triggered ? It calls ChildForm.SaveEntity rather than just FormBase.SaveEntity ? Not sure which value you see. Could it be that SaveChanges is also triggered for example when the child form looses the focus ? In this case, the parent form wouldn't save anything at all (as it has been already saved). Or do you see the original values found in the db ? Where do you see them ? (how did you realize something is wrong ?)

    I don't remember to have ever heard about this kind of issue but hopefully it will make sense once the root cause is discovered...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".




    Tuesday, July 10, 2012 11:57 AM
  • I know it calls my overridden method, I throw a notimplementedexception in the base class to ensure I've overridden in my derived class. I've stepped through with the debugger so I 'm confident my program flow is as expected. Here's something else odd that I've discoverd though.

    I've created a test form (not mdi this time) with a toolbar and a button. When the form loads it creates the other form (previously the mdi child form as discussed above, the one that contains the public SaveEntity method) . If I now call SaveEntity either from the toolbar click or button press, neither work.

    If I change my test form to an mdi container and create the child form as a child, the toolbar click still doesn't work, but the button press now works i.e. it updates the record.

    There's definitely something UI related going on under the bonnet which seems to be affecting the context.

    I first realised something was wrong when I was checking the database records in SSMS, after having saved the change in my app, to ensure that the save was committed to the db.


    Gavin Williams

    Tuesday, July 10, 2012 12:26 PM
  • If using AttachDbFileName I saw sometimes the wrong file (the one that is in the solution rather than the one copied to the output directory) being checked leading to believe the update didn't take place (but here you would see the same issue wether or not you are using a button or menu item click ?).

    Looks definitely weird. Let me know if you find something else (test InvokeRequired to see what it gives ?). I'll give this a quick try to see if I have the same behavior here...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    Tuesday, July 10, 2012 12:53 PM
  • Just for info. I've added a toolstrip control to my child form and called context.savechanges directly from the toolstripbutton click event and it doesn't save the changes. It looks like toolstrip control (and probably menustrip too)+EF is a definite fail :(

    Gavin Williams

    Tuesday, July 10, 2012 1:16 PM
  • I've just had a eureka moment. It's caused by the fact that when you click a toolstrip button, the textbox in which you changed the value does not lose focus, therefore the edit in effect hasn't finished yet. This explains why the normal button works, because as soon as you click it, the button takes focus from the textbox.

    So, is there an "approved" method of dealing with this, or can I just be sneaky and change focus to a textbox on the parent form which is outside the visible area whrn you click a toolbar (which works).


    Gavin Williams

    Tuesday, July 10, 2012 1:58 PM