I am developing a UWP app, which can download files concurrently and write file data to SQLite database. I have used sqlite-net-pcl as SQLite wrapper. I get DB exceptions when I am running multiple database transactions. This is sample code how I am using SQLite.
AppSQLite.cs
//Database name
public static readonly string DATABASE_NAME = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "App.db");
SQLiteAsyncConnection conn = null;
/// <summary>
/// Constructor
/// </summary>
public SASQLite()
{
try
{
conn = new SQLiteAsyncConnection(DATABASE_NAME);
CreateTables();
}
catch (Exception er)
{
Log(er);
}
}
public async Task CreateTables()
{
try
{
await CreateUserTable();
await CreateUserProject();
await CreateUserFacility();
await CreateTopic();
//More tables to create
}
catch (Exception er)
{
Log(er);
}
finally
{
await conn.CloseAsync();
}
AppUtils.PrintDebug("=========End", CLASS_NAME, "CreateTables");
}
// All the table creations similar to this
private async Task CreateUserTable()
{
if (conn != null)
{
await conn.CreateTableAsync<User>();
}
else
{
//null connection
}
}
TopicDAL.cs
/// <summary>
/// add topic to topic table
/// </summary>
/// <param name="topicModel"></param>
/// <returns></returns>
public static async Task AddTopic(TopicModel topicModel)
{
try
{
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(AppSQLite.DATABASE_NAME);
// create a new Id for the db entry
string id = Guid.NewGuid().ToString();
Topic topic = new Topic()
{
Id = id,
TopicId = topicModel.Id,
TopicTitle = topicModel.TopicTitle,
TopicContent = topicModel.Content,
DocumentId = topicModel.DocumentId
};
await conn.InsertAsync(topic);
await conn.CloseAsync();
}
catch (Exception er)
{
Log(ex);
}
}
}
Write data to database
......
foreach (IXmlNode topicElement in TopicElementList)
{
if (topicElement.NodeType == NodeType.ElementNode)
{
string itemType = null;
if (topicElement.Attributes.GetNamedItem("itemType") != null)
{
itemType = topicElement.Attributes.GetNamedItem("itemType").NodeValue as string;
}
if (itemType == "Topic")
{
// Create topic using topicElement
............
await TopicDAL.AddTopic(topic);
}
................................
}
}
There can be 1000 topics for each download and user can do 100 of such downloads. So this fails with different DB exceptions as followings.
TopicDAL::AddTopic::=========Start TopicDAL::AddTopic::=========Id : d94a0a04-4bea-4b68-8757-cb304e36d16b Exception thrown: 'System.NullReferenceException' in System.Private.CoreLib.dll TopicDAL::AddTopic::=========Exception : System.NullReferenceException: Object reference not set to an instance of an object. at SQLite.PreparedSqlLiteInsertCommand.ExecuteNonQuery(Object[] source) at SQLite.SQLiteConnection.Insert(Object obj, String extra, Type objType) at SQLite.SQLiteAsyncConnection.<>c_DisplayClass33_0
1.<WriteAsync>b_0() at System.Threading.Tasks.Task1.InnerInvoke() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location where exception was thrown --- at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) --- End of stack trace from previous location where exception was thrown --- at App.Repository.DAL.TopicDAL.AddTopic(TopicModel topicModel)=========Exception : System.ArgumentNullException: SafeHandle cannot be null. Parameter name: pHandle at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success) at SQLitePCL.SQLite3Provider_e_sqlite3.NativeMethods.sqlite3_prepare_v2(sqlite3 db, Byte* pSql, Int32 nBytes, IntPtr& stmt, Byte*& ptrRemain) at SQLitePCL.SQLite3Provider_e_sqlite3.SQLitePCL.ISQLite3Provider.sqlite3_prepare_v2(sqlite3 db, utf8z sql, IntPtr& stm, utf8z& tail) at SQLitePCL.raw.sqlite3_prepare_v2(sqlite3 db, utf8z sql, sqlite3_stmt& stmt) at SQLite.SQLite3.Prepare2(sqlite3 db, String query) at SQLite.PreparedSqlLiteInsertCommand.ExecuteNonQuery(Object[] source) at SQLite.SQLiteConnection.Insert(Object obj, String extra, Type objType) at SQLite.SQLiteAsyncConnection.<>c_DisplayClass33_0
1.<WriteAsync>b_0() at System.Threading.Tasks.Task1.InnerInvoke() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location where exception was thrown at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) --- End of stack trace from previous location where exception was thrown ---
Can you please guide me if there is any issue withthis mplementation? If it is related to SQLite wrapper what can be the best option, to use in this scenario?