none
How to rollback a DataSet to a given point? RRS feed

  • Question

  • Hello,

    My application has a DataSet.

    When I reach a certain point in my program (call it a "savepoint") I need to keep track of all the changes made to the DataSet in order to - if requested - be able to roll back these and only these changes.

    How can I undo all the changes that have happened to the DataSet since the savepoint?

    Indeed can I not simply call "RejectChanges" because this would rollback also the changes that took place before the savepoint .. ?

    Thank you,

    Danny

    Thursday, June 7, 2018 4:23 PM

Answers

All replies

  • Hi Danny,

    Unfortunately, you can't do a "savepoint" that way. The best you could do, when creating a "savepoint", is to make a copy of your DataSet:

    DataSet SavePoint = MyDataSet.Copy();

    And then, if requested to roll back, just do the same thing in reverse, using SavePoint.Copy();

    The .Copy() *does* preserve the changes, which you would want it to do.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Thursday, June 7, 2018 6:12 PM
  • Thank you Bonnie for your "lightning fast" reply :-) Yes, that would be my "last resort solution" too. I somewhat hesitate to copy my (large) DataSet .. Thanks again!
    Friday, June 8, 2018 8:35 AM
  • Hi Danny ... sorry that I didn't think of this earlier, it just popped into my head this morning. You should make use of reading and writing a DiffGram for saving your savepoint DataSet. This will write it to a file.

    MyDataSet.WriteXml("SavePoint.xml", XmlWriteMode.DiffGram);

    and then, to read it back in, and preserve the changes:

    MyDataSet.ReadXml("SavePoint.xml", XmlReadMode.DiffGram);


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Friday, June 8, 2018 4:06 PM
  • Hi Bonnie. Thank you. I have no experience with DiffGrams (yet), but will study your proposed solution. However, from my current understanding I wonder how this solution is different from your initial solution whereby you copy the DataSet? True, the DiffGram will not consume internal memory, because it is written to disk, but I will take much longer to generate because it has to be written to disk ..? 
    Monday, June 11, 2018 8:06 AM
  • Hi Danny,

    You could storage it into a temp variable or a static variable, it will be lost after shot down the application.

    Best regards,

    Zhanglong


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, June 12, 2018 7:38 AM
    Moderator
  • Hi Bonnie. Thank you. I have no experience with DiffGrams (yet), but will study your proposed solution. However, from my current understanding I wonder how this solution is different from your initial solution whereby you copy the DataSet? True, the DiffGram will not consume internal memory, because it is written to disk, but I will take much longer to generate because it has to be written to disk ..? 

    This is different from my initial solution because you don't copy anything, therefore you're not using up memory. You're writing your current DataSet to disk (as a DiffGram) ... no extra memory required.

    And, yes, there's always a trade-off, isn't there? Writing to disk does take time ... but you *did* say that you were hesitant to consume too much memory making an in-memory copy of your DataSet.

    You could make use of Task.Run() to write your DataSet to disk in a separate thread that won't interfere with the UI. I haven't tried this, but it should work. The syntax would be something like this:

    Task.Run( () =>
    {
        MyDataSet.WriteXml("SavePoint.xml", XmlWriteMode.DiffGram);
    });


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Tuesday, June 12, 2018 4:07 PM
  • Thanks Bonnie. But even if I have it saved in a separate thread, I wonder what will happen if I start modifying the DataSet in my main thread whilst it is being saved by the other thread? Unless I make a in-memory copy of it to save, which is precisely what I wanted to avoid :-) .. Also, as long as it has not been saved, I will not be able to a rollback. So in short, I must wait for the save to have happened ..
    Thursday, June 14, 2018 11:33 AM
  • Hey Danny,

    Well, as it turns out, the Task.Run() option can be problematic if the DataSet changes. And, in fact, it can be problematic even if you make a .Copy() of it!!  I tried two options:

    // first try
    Task.Run(() =>
    {
        MyDataSet.Copy().WriteXml("testfile.xml", XmlWriteMode.DiffGram);
    });
    
    // second try
    Task.Run(() =>
    {
        DataSet dsCopy = MyDataSet.Copy();
        dsCopy.WriteXml("testfile.xml", XmlWriteMode.DiffGram);
    });
    

    I was thinking that the first one would be preferable, because the Copy wouldn't remain in memory very long. However neither one worked reliably if a change was made too soon. The problem has to do with something called "Closures". See my blog post about this ( https://geek-goddess-bonnie.blogspot.com/2017/03/fire-and-forget.html ). I don't think I fully understand it, but there's a link in my blog post to a blog post by Eric Lippert, who's really good at explaining things.

    To be honest, I wondered if it would be a problem for just that reason, and in fact, I was initially thinking of posting sample code for you using the old tried-and-true ThreadPool.QueueUserWorkItem, which is what I always use. But, I thought I'd post something using newer syntax (the Task.Run). There are probably other ways to write this with Task.Run(), but it's not something I've played around with all that much. Anyway, using the QueueUserWorkItem, and using a Copy (which shouldn't exist in memory very long at all) works perfectly every time.

    // Put this in place of the Task.Run()code block. 
    ThreadPool.QueueUserWorkItem(new WaitCallback(SaveDiffGram), MyDataSet.Copy());
    
    //The only downside is that you also need to add a Callback method
    private void SaveDiffGram(object ds)
    {
        ((DataSet)ds).WriteXml("testfile.xml", XmlWriteMode.DiffGram);
    }
    

    This should be an OK solution for you, other than the little bit of extra memory it uses briefly. Unfortunately, a Copy() can't be avoided (since you're concerned about changes being made before it's written) and the in-line Copy() shouldn't hold on to the memory for too long. The only other way to avoid the Copy is to Write the file "in-line", in which case everything has to wait for it to complete.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Thursday, June 14, 2018 8:48 PM