{"id":106,"date":"2011-07-22T11:24:53","date_gmt":"2011-07-22T03:24:53","guid":{"rendered":"https:\/\/www.techcoil.com\/blog\/?p=106"},"modified":"2018-09-02T22:51:25","modified_gmt":"2018-09-02T14:51:25","slug":"my-experience-with-system-data-sqlite-in-c","status":"publish","type":"post","link":"https:\/\/www.techcoil.com\/blog\/my-experience-with-system-data-sqlite-in-c\/","title":{"rendered":"My experience with System.Data.SQLite in C#"},"content":{"rendered":"<p>It was time when simple file IO like <a title=\"How to save and load objects to and from file in C#\" href=\"http:\/\/www.techcoil.com\/blog\/quick-references\/how-to-save-and-load-objects-to-and-from-file-in-c\/\" target=\"_blank\">object serialization to file<\/a>, was not enough to manage data persistence in the .NET application that I had been building. Prior to encountering this situation, I had always wanted to gain practical experience with <a href=\"http:\/\/www.sqlite.org\/\" target=\"_blank\">SQLite<\/a>. With some googling, I found a <a href=\"https:\/\/system.data.sqlite.org\/index.html\/doc\/trunk\/www\/index.wiki\" target=\"_blank\">.NET wrapper around the SQLite library<\/a> that I could use in my application. This post documents my experience with using the System.Data.SQLite wrapper.<\/p>\n<h3>Including the System.Data.SQLite into your project<\/h3>\n<p>The creator of System.Data.SQLite made it very easy for developers to use SQLite in their .NET projects: the whole SQLite database is contained within a single dll. As I was developing a .NET 2.0 project, I chose to download the <a href=\"http:\/\/sourceforge.net\/projects\/sqlite-dotnet2\/files\/SQLite%20for%20ADO.NET%202.0\/\" target=\"_blank\">1.0.66.0 version<\/a>. Just add a reference to one of the three flavors of <strong>System.Data.SQLite.dll<\/strong> (Win32, Itanium and x64) and you can start using SQLite in your project.<\/p>\n<h3>Initializing a connection to SQLite<\/h3>\n<p>As with most sql databases, the first action to perform on the database is to connect to it. Connecting to the database is performed via the System.Data.SQLite.SQLiteConnection class. The following code segment attempts to connect to the database file \"sample.s3db\" in the same working directory as the project executable.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nstring dbConnectionString = @&quot;Data Source=sample.s3db&quot;;\r\nSQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);\r\nsqliteCon.Open();\r\n<\/pre>\n<p>If the database file does not exist, a new one will be created. If there exists a file with the same name, the code will read the file as a SQLite database file and an SQLiteException will be thrown if the file is not a valid one.<\/p>\n<h3>Defining a data structure to store my application data<\/h3>\n<p>Suppose that I need to store the name and username of users of my application, I will define the table with the SQL CREATE syntax:<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\nCREATE TABLE &#x5B;AppUser] (\r\n    &#x5B;name] TEXT NULL,\r\n    &#x5B;username] TEXT NULL\r\n)\r\n<\/pre>\n<p>Then, I will use the following .NET code to implement the table structure into my SQLite database instance:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ Open connection to database\r\nstring dbConnectionString = @&quot;Data Source=sample.s3db&quot;;\r\nSQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);\r\nsqliteCon.Open();\r\n\r\n\/\/ Define the SQL Create table statement\r\nstring createAppUserTableSQL = &quot;CREATE TABLE &#x5B;AppUser] (&quot; +\r\n    &quot;&#x5B;name] TEXT NULL,&quot; +\r\n    &quot;&#x5B;username] TEXT  NULL&quot; +\r\n    &quot;)&quot;;\r\n\r\nusing (SQLiteTransaction sqlTransaction = sqliteCon.BeginTransaction())\r\n{\r\n    \/\/ Create the table\r\n    SQLiteCommand createCommand = new SQLiteCommand(createAppUserTableSQL\r\n                                                          , sqliteCon);\r\n    createCommand.ExecuteNonQuery();\r\n    createCommand.Dispose();\r\n\r\n    \/\/ Commit the changes into the database\r\n    sqlTransaction.Commit();\r\n} \/\/ end using\r\n\r\n\/\/ Close the database connection\r\nsqliteCon.Close();\r\n<\/pre>\n<h3>Inserting, updating and deleting records from a data structure<\/h3>\n<p>Inserting, updating and deleting records can be performed via SQL INSERT, UPDATE and DELETE statements:<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n-- Insert example\r\nINSERT INTO AppUser(name, username) VALUES('Tommy', 'Tommy_83')\r\n\r\n--Update example\r\nUPDATE AppUser SET name =  'Tom' WHERE username = 'Tommy_83'\r\n\r\n--Delete example\r\nDELETE FROM AppUser WHERE name='Tom' AND username='Tommy_83'\r\n<\/pre>\n<p>The coding to perform these three kind of statements are of the same form:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ Performs an insert, change contents of sqlStatement to perform\r\n\/\/ update or delete.\r\nstring sqlStatement = &quot;INSERT INTO AppUser(name, username) VALUES('Tommy', 'Tommy_83')&quot;;\r\nstring dbConnectionString = @&quot;Data Source=sample.s3db&quot;;\r\nSQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);\r\nsqliteCon.Open();\r\nusing (SQLiteTransaction sqlTransaction = sqliteCon.BeginTransaction())\r\n{\r\n    SQLiteCommand command = new SQLiteCommand(sqlStatement , sqliteCon);\r\n    command .ExecuteNonQuery();\r\n    sqlTransaction.Commit();\r\n}\r\n<\/pre>\n<h3>Performing database queries<\/h3>\n<p>Database queries can be performed via the SQL SELECT statement:<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n--Select the name and username column of all users\r\nSELECT user, username FROM AppUser\r\n<\/pre>\n<p>The following code segment retrieves the user and username columns for every record in the AppUser table and print them on the Console.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ Connect to database\r\nstring dbConnectionString = @&quot;Data Source=sample.s3db&quot;;\r\nSQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);\r\nsqliteCon.Open();\r\n\r\n\/\/ Execute query on database\r\nstring selectSQL = &quot;SELECT user, username FROM AppUser&quot;;\r\nSQLiteCommand selectCommand = new SQLiteCommand(selectSQL, sqliteCon);\r\nSQLiteDataReader dataReader = selectCommand.ExecuteReader();\r\n\r\n\/\/ Iterate every record in the AppUser table\r\nwhile (!dataReader.Read())\r\n{\r\n   Console.WriteLine(&quot;User: &quot; + dataReader.GetString(0)\r\n        + &quot; Username: &quot; + dataReader.GetString(1));\r\n}\r\ndataReader.Close();\r\nsqliteCon.Close();\r\n<\/pre>\n<p><strong>Note:<\/strong> Unlike other database api, the GetXXX methods of the SQLiteDataReader in the wrapper that I used do not accept a column name as input for retrieval of data from a particular column. Instead, the GetXXX method accepts a index input, which is the position of the column data as specified in the SQL SELECT statement. In this case, because I had specified the user column followed by the username column in my SQL SELECT statement, the index 0 will represent the data from the 'user' column and the index 1 will represent the data from the 'username' column.<\/p>\n<h3>Some problems that took me some time to solve<\/h3>\n<p>My attempt to integrate SQLite into my .NET application wasn't as smooth as I had wanted it to be. The following are some exceptions that I solved after I had integrated SQLite into my application.<\/p>\n<h4>System.Data.SQLite.SQLiteException: The database file is locked cannot rollback transaction - SQL statements in progress<\/h4>\n<p>This is the first bizarre exception that I encountered in my application log. The source of the exception came from the code segment of the following form:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ Connect to database\r\nstring dbConnectionString = @&quot;Data Source=sample.s3db&quot;;\r\nSQLiteConnection sqliteCon = new SQLiteConnection(dbConnectionString);\r\n\r\n\/\/ Search the table for user Tommy\r\nstring selectSQL = &quot;SELECT user FROM AppUser WHERE user = 'Tommy'&quot;;\r\nSQLiteCommand selectCommand = new SQLiteCommand(selectSQL, sqliteCon);\r\nSQLiteDataReader dataReader = selectCommand.ExecuteReader();\r\n\r\n\/\/ If Tommy is in the table\r\nif (dataReader.Read())\r\n{\r\n    \/\/ Update his username\r\n    using (SQLiteTransaction sqlTransaction = sqliteCon.BeginTransaction())\r\n    {\r\n        \/\/ Update the expiry date of the application\r\n        string updateSQL = &quot;UPDATE AppUser SET username = 'Tommy_85'&quot; +\r\n                                   &quot; WHERE user = 'Tommy'&quot;;\r\n        SQLiteCommand updateCommand = new SQLiteCommand(updateSQL, sqliteCon);\r\n        updateCommand.ExecuteNonQuery();\r\n        sqlTransaction.Commit();\r\n    }\r\n}\r\nelse\r\n{\r\n    \/\/ Insert Tommy as a new user\r\n    using (SQLiteTransaction sqlTransaction = sqliteCon.BeginTransaction())\r\n    {\r\n        string insertSQL = &quot;INSERT INTO AppUser(user, username)&quot; +\r\n                                 &quot; VALUES ('Tommy', 'Tommy_86')&quot;;\r\n        SQLiteCommand insertCommand = new SQLiteCommand(insertSQL, sqliteCon);\r\n        insertCommand.ExecuteNonQuery();\r\n        sqlTransaction.Commit();\r\n    }\r\n}\r\ndataReader.Close();\r\nsqliteCon.Close();\r\n<\/pre>\n<p>While the following code will work well in some other database system, SQLite does not like this way of data manipulation. The reason is that SQLite will lock the table for every data manipulation action (SELECT, INSERT, UPDATE, DELETE). In the above code segment, when Tommy is in the database table, the call to dataReader.Read() will lock the AppUser table. And when subsequent code attempts to update to the AppUser table, the code could not proceed and the exception would be thrown.<\/p>\n<p>I was able to solve the exception by rewriting the code to close the SQLiteDataReader instance before subsequent code attempts to perform an update or insert on the AppUser table.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ Open connection to database\r\nSQLiteConnection sqliteCon = new SQLiteConnection(this._dbConnectionString);\r\nsqliteCon.Open();\r\n\r\n\/\/ Search the table for user Tommy\r\nstring selectSQL = &quot;SELECT user FROM AppUser&quot; +\r\n                          &quot; WHERE user = 'Tommy'&quot;;\r\nSQLiteCommand selectCommand = new SQLiteCommand(selectSQL\r\n                                                   , sqliteCon);\r\nSQLiteDataReader dataReader = selectCommand.ExecuteReader();\r\n\r\n\/\/ Use a variable to store the result of the search\r\nbool tommyExists = dataReader.Read();\r\ndataReader.Close();\r\n\r\n\/\/ If Tommy is in the table\r\nif (tommyExists)\r\n{\r\n    \/\/ Update his username\r\n    using (SQLiteTransaction sqlTransaction = sqliteCon.BeginTransaction())\r\n    {\r\n        \/\/ Update the expiry date of the application\r\n        string updateSQL = &quot;UPDATE AppUser SET username = 'Tommy_85'&quot; +\r\n                                   &quot; WHERE user = 'Tommy'&quot;;\r\n        SQLiteCommand updateCommand = new SQLiteCommand(updateSQL\r\n                                                            , sqliteCon);\r\n        updateCommand.ExecuteNonQuery();\r\n        sqlTransaction.Commit();\r\n    }\r\n}\r\nelse\r\n{\r\n    \/\/ Insert Tommy as a new user\r\n    using (SQLiteTransaction sqlTransaction = sqliteCon.BeginTransaction())\r\n    {\r\n        string insertSQL = &quot;INSERT INTO AppUser(user, username)&quot; +\r\n                                 &quot; VALUES ('Tommy', 'Tommy_86')&quot;;\r\n        SQLiteCommand insertCommand = new SQLiteCommand(insertSQL, sqliteCon);\r\n        insertCommand.ExecuteNonQuery();\r\n        sqlTransaction.Commit();\r\n    }\r\n}\r\nsqliteCon.Close();\r\n<\/pre>\n<h4>System.Data.SQLite.SQLiteException: Unable to open the database file unable to open database file<\/h4>\n<p>This exception was non deterministic and I took longer to attempt solve it. There are many people in the web who had encountered the same exception but their solutions does not apply to my problem. Among the many suggestions, I thought that permission issues with the database file and the folder in which the database file resides in appeared to be the main culprit. However for my case, I was able to perform some database operations before I encounter the exception, even those operations that threw the exception. In the end, it turned out that it was my attempt in synchronizing access to a single SQLiteConnection instance that caused the exception. After I modified my code to create instances of the SQLiteConnection object for every database operation, the exception disappears from my log.<\/p>\n<h4>Other topics that may interest you<\/h4>\n<ul>\n<li><a title=\"How to build a web based user interaction layer in C#\" href=\"http:\/\/www.techcoil.com\/blog\/how-to-build-a-web-based-user-interaction-layer-in-c\/\" target=\"_blank\">How to build a web server layer in your C# program.<\/a><\/li>\n<li><a title=\"Uploading large HTTP multipart request with System.Net.HttpWebRequest in C#\" href=\"http:\/\/www.techcoil.com\/blog\/uploading-large-http-multipart-request-with-system-net-httpwebrequest-in-c\/\" target=\"_blank\">How to upload large HTTP multipart request in C#<\/a><\/li>\n<li><a title=\"Downloading a file via HTTP post and HTTP get in C#\" href=\"http:\/\/www.techcoil.com\/blog\/downloading-a-file-from-via-http-post-and-http-get-in-c\/\" target=\"_blank\">How to download file from a HTTP server in C#<\/a><\/li>\n<li><a title=\"Implementing client-server communication using serialization and TCP\/IP in C#\" href=\"http:\/\/www.techcoil.com\/blog\/implementing-client-server-communication-using-serialization-and-tcpip-in-c\/\" target=\"_blank\">How to implement serialization over TCP\/IP in C#<\/a><\/li>\n<li><a title=\"How to save and load objects to and from file in C#\" href=\"http:\/\/www.techcoil.com\/blog\/how-to-save-and-load-objects-to-and-from-file-in-c\/\">How to save and load objects to and from file in C#<\/a><\/li>\n<\/ul>\n\n      <ul id=\"social-sharing-buttons-list\">\n        <li class=\"facebook\">\n          <a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fwp.me%2Fp245TQ-1I\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n            <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Facebook.png\" alt=\"Facebook icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"twitter\">\n          <a href=\"https:\/\/twitter.com\/intent\/tweet?text=&url=https%3A%2F%2Fwp.me%2Fp245TQ-1I&via=Techcoil_com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Twitter.png\" alt=\"Twitter icon\"> Tweet\n          <\/a>\n        <\/li>\n        <li class=\"linkedin\">\n          <a href=\"https:\/\/www.linkedin.com\/shareArticle?mini=1&title=&url=https%3A%2F%2Fwp.me%2Fp245TQ-1I&source=https:\/\/www.techcoil.com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/linkedin.png\" alt=\"Linkedin icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"pinterest\">\n          <a href=\"https:\/\/pinterest.com\/pin\/create\/button\/?url=https%3A%2F%2Fwww.techcoil.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F106&description=\" class=\"pin-it-button\" target=\"_blank\" role=\"button\" rel=\"nofollow\" count-layout=\"horizontal\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Pinterest.png\" alt=\"Pinterest icon\"> Save\n          <\/a>\n        <\/li>\n      <\/ul>\n    ","protected":false},"excerpt":{"rendered":"<p>It was time when simple file IO was not enough to manage data persistence in the .NET application that I had been building. Prior to encountering this situation, I had always wanted to gain practical experience with <a href=\"http:\/\/www.sqlite.org\/\" target=\"_blank\">SQLite<\/a>. With some googling, I found a .NET wrapper around the SQLite library that I could use in my application. This post documents my experience with using the System.Data.SQLite wrapper. <\/p>\n","protected":false},"author":1,"featured_media":1190,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"footnotes":""},"categories":[375],"tags":[20,26,27],"jetpack_featured_media_url":"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/SQLite-and-C-Sharp-logos.gif","jetpack_shortlink":"https:\/\/wp.me\/p245TQ-1I","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/106"}],"collection":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/comments?post=106"}],"version-history":[{"count":0,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/106\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media\/1190"}],"wp:attachment":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media?parent=106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/categories?post=106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/tags?post=106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}