A couple of issues

Jan 12, 2011 at 4:02 AM

Hi Sergey,

First, thank you for the library.  It is helping us a great deal in our WP7 project.   There are some issues we hope you can help look at.

1.  Currently, we face a problem which occasionally occurs when the app is opened.  An exception is thrown when the database is opened.   The stack trace reveals the Database.LoadTable() method (invoked during Database.OpenDatabase) as the original place where the exception is thrown.

        internal void LoadTable(IsolatedStorageFileStream tableStream, Type tableType)
            string content;
            using (StreamReader reader = new StreamReader(tableStream))
                content = reader.ReadToEnd(); // content is null

                if (!string.IsNullOrEmpty(_password))
                    content = Cryptography.Decrypt(content, _password);

            using (StringReader stringReader = new StringReader(content))
                XmlSerializer serializer = new XmlSerializer(tableType);
                ITable table = (ITable)serializer.Deserialize(stringReader); // exception here
                table.SetTableDefinition(_databaseName, _password);

                List<ITable> tables = new List<ITable>(_tables);
                var tableToRemove = (from oneTable in tables
                                     where oneTable.RowType == table.RowType
                                     select oneTable).FirstOrDefault();
                _tables = new ReadOnlyCollection<ITable>(tables);

For some reason, the content variable is an empty string ("", not null) and that leads to the XmlSerializer to throw exception when the Deserialize(stringReader) is invoked.  We confirm that we call OpenDatabase() after making sure the database exists by calling DoesDatabaseExist() method.   Besides, when we create the database for the first time, we did invoke all the necessary Database.CreateTable<T>() method to setup all tables.  

2.  We apply the singleton pattern for the database, that is we open the database once (during application launching/activation) and keep it as a static field in the app.  When the app is closed/activated (or when there's an unhandled exception), we would invoke Database.Save().  We hope to improve the app performance and at the same time avoid unnecessary IsolatedStorage transactions, which could be a source of potential errors.  Do you think this is a good/correct use of the library?  Is there any chance this is the cause of #1?

Thanks again for the library and we look forwards to hearing from you.

Jan 12, 2011 at 12:38 PM

Hello, buunguyen.

On #2, I am a little weary of calling Save() on exceptions.  This does not seem like a good idea to me.  Other than that, I do not see any issues with your pattern, although in my own application in the App Store, I call Save() when the user changes the data.

It is very hard to debug the issue your describe in #1.  Did you check to make sure all your classes have at least one property?  Do you use encryption?  Do you use asynchronous save?

I am guessing, the error occurs because the Save() operation is interrupted in the progress or possibly because two different threads are stomping on each other.

Since I do not have enough information, all I can think of is treat the symptom.  To do so I could add check for string.IsNullOrEmpty(content) before performing the read action.  Please let me know if you would like me to make the change.  I am not opposed to it.

On a side note, I would suggest that you change your pattern and save when the data is changed by the user.  You do not need static vairable though, just application level field.  Static variables are not unloaded until applicaiotn domain goes down, so it is less predictable.  In general, I try not to use static variables.  In my applicaiton I keep reference to DB inside my view model instead of Application level variable,

Jan 12, 2011 at 1:46 PM
Edited Jan 12, 2011 at 1:47 PM

Hi Sergey,

Thanks for the quick response.  You're right, invoking Save() on exception doesn't feel good to me too.  But since the save-once-on-closing pattern is adopted, I can't think of a way to assure hard-earned data of the user isn't wiped out due to an unexpected exception.  In our app, there are 4 tables, one of which could contain more than a thousand objects, and many modification actions;  calling Save() after every one of them would decrease the app performance significantly since the Save() operation seems to save the whole database and all of its tables, not just the newly added record.  (We did measure and notice that it took ~200ms per Save() invocation.)

Regarding state, unless we get away with the save-once-on-closing pattern, I suppose we still need to keep the db in some global state.  At first, we put it in PhoneApplicationService.State until we started receiving exception on deactivation because WP7 attempted to persisted things inside phone app state and it threw when saving the db object.  So we ended up using static state.

Regarding #1:

  • DB encryption is not used
  • Asynchronous save is not used
  • Save() is only invoked in the UI thread
  • All entity classes have at least one property - there's a class having a property of type List<string> but I don't think that would cause any issue because the Save() runs fine

I don't really understand the string.IsNullOrEmpty(content) suggestion.  If you could just go ahead making the change that you think will fix the symptom then it's much appreciated.


Jan 13, 2011 at 12:41 AM
Edited Jan 13, 2011 at 12:43 AM

Hello, buunguyen.

I just posted release.  You can find it under All Downloads.  It is called LoadTable Fix Release.  I do not want to make it a recommended release until you run through it a few times.

I want to mention again that the error is likely caused by an interruption in the Save process.  This release will treat the symptom, not the problem.  I think you need to try to do more research to duplicate the issue.



Jan 13, 2011 at 3:02 AM

Hi Sergey,

Thanks for that.  I've included the code in my project.  If I understand a the root cause, I would post here.