Windows Phone 8.1 SQLite: How to Store Data in Database

Introduction

If you want to implement a SQLite database application for Windows Phone 8.0, my previous article might help. This article explains "SQLite support in Windows Phone Store 8.1". This article is compared with my previous article, so that we can easily understand the changes in WP8.0 and WP8.1 to setup SQLite environment.

SQLite

Requirements

  • This sample is targeted for the Windows Phone Store 8.1 OS. So make sure you've downloaded and installed the Windows Phone 8.1 SDK. For more information, see Get the SDK.

  • I assume you will test your app in the Windows Phone emulator. If you want to test your app on a phone, you need to take some additional steps. For more info, see Register your Windows Phone device for development.

  • This article assumes you're using Microsoft Visual Studio Express 2013 for Windows.

Table of Contents

Some extensions need to be installed to interact with Sqlite from your WP8.1 app. And now it is very easy to set up the SQLite environment in our apps. So this article covers SQLite at the beginners level like this.

  1. How to set up the SQLite environment
  2. How to perform all the SQLite CRUD operations
  3. How to bind SQLite data to a listbox
  4. How to explore "SQLite" database data

Description

SQLite is a very lightweight database. In this tutorial I'll explain how to write classes to handle all the SQLite operations. So let's start with the preceding hierarchy that was previously discussed in the "Table of Contents".

1. How to set up the SQLite environment

Sqlite is not available directly in Windows Phone. Don't worry however since it is now very easy to set up SQLite in Windows Phone apps. We need to use only two steps (instal SQLite for Windows Phone SDK and instal the sqlite-net-wp8 package).

    1.1 Installing SQLite for Windows Phone SDK

    It's worth noting that the current version (3.8.8.0) has a flaw in the package metadata that prevents it from showing in the Visual Studio 2013 "Tools | Extensions and Updates" page. You need to go to the web page, download and install the VSIX package by yourself:

    SQLite for Windows Phone SDK

    Click on Download and you can open it directly when downloading, authorize installation and click install when ready.

    click install

    Open Microsoft Visual Studio Express 2013 for Windows and then create a new project of type Blank App (for example SQLiteWp8.1).

    blank app

    Open Solution Explorer then right-click on the "References" folder of your current project.

    Open Solution explorer

    Then add the reference to the "SQLite for Windows Phone 8.1" library:

    SQLite for WindowsPhone

    When done, you can see that the proper references to SQLite and the Visual C++ 2013 Runtime have been added to respective project:

    references

    You may have already noticed that the references show warning symbols. To resolve that the next thing to do is, before compiling the solution, change the architecture of the target platform. This is because the SQLite engine is written in C ++ and the default target platform set in the project is "Any CPU". This mode is not supported. To do this in the main menu of Visual Studio we must use the command "Compile", then go to the "Configuration Manager", as shown in the figure.

    Configuration Manager

    In the Configuration Manager dialog, we have several choices of platforms, "Any CPU" (the default), "ARM", "x64" and "x86".

    platforms

    We need to select the target platform second, where we are trying the application. If we use a tablet, or a phone with ARM processor, we need to select the ARM platform. If we are using the emulator or in the case of Windows Phone, a PC in the case of Windows, we must select x86 or x64, everything depends on your processor if 32 or 64 bits. In my case, I tried the sample application on a emulator with Windows Phone OS 8.1, so I chose the x86 configuration.

    1.2 Installing SQLite-net package:

    After installing the library for SQLite, we need the SQLite-net NuGet package. With this library, we will be able to do all the operations that are normally done in a database, such as Insert, Delete, Update and run search queries. SQLite-net also offers an approach typical of ORM. This package provides the two helper classes SQLite.cs and SQLiteAsync.cs, so to install it right-click on your project (in other words in my case the project name is SQLiteWp8.1) then click on "Manage NuGet Packages" and search for "SQLite-net" then click on the "Install" button. Then we should see the following dialog:

    *SQLite net

    ***Wow now the entire SQLite is set up and the process is complete, so now we will work with all the CRUD operations***

2. How to perform all the SQLite CRUD operations

Note: From this step on-ward, most of the content will be the same as in my previous article. Please note that a few changes were made in this article.

So its time to perform all the SQLite Create, Read, Update, Delete (CRUD) operations. So my thought for this sample is to make a single "DatabaseHelperClass.cs" class for the entire application and handle the SQLite operations with this helper class. Let's first see my table structure.

DatabaseHelperClass

Here I am trying to create table named "Contacts" in the "ContactsManager.sqlite" database. So my class "Contacts" has all the getter and setter methods (Id, Name, PhoneNumber, CreatedDate) to maintain a single contact as an object.

C# Code

  1. public class Contacts  
  2. {  
  3.     //The Id property is marked as the Primary Key  
  4.     [SQLite.PrimaryKey, SQLite.AutoIncrement]  
  5.     public int Id { getset; }  
  6.     public string Name { getset; }  
  7.     public string PhoneNumber { getset; }  
  8.     public string CreationDate { getset; }  
  9.     public Contacts()  
  10.     {  
  11.         //empty constructor  
  12.     }  
  13.     public Contacts(string name, string phone_no)  
  14.     {  
  15.         Name = name;  
  16.         PhoneNumber = phone_no;  
  17.         CreationDate = DateTime.Now.ToString();  
  18.     }  
  19. }  

 

    2.1 Writing DatabaseHelper Class to handle database operations (CRUD operations):

    C# Code

    1. //This class for perform all database CRUD operations   
    2. public class DatabaseHelperClass   
    3. {   
    4.     SQLiteConnection dbConn;   
    5.       
    6.     //Create Tabble   
    7.     public async Task<bool> onCreate(string DB_PATH)   
    8.     {   
    9.         try   
    10.         {   
    11.             if (!CheckFileExists(DB_PATH).Result)   
    12.             {   
    13.                 using (dbConn = new SQLiteConnection(DB_PATH))   
    14.                 {   
    15.                     dbConn.CreateTable<Contacts>();   
    16.                 }   
    17.             }    
    18.             return true;   
    19.         }   
    20.         catch   
    21.         {   
    22.             return false;   
    23.         }   
    24.     }   
    25.     private async Task<bool> CheckFileExists(string fileName)   
    26.     {   
    27.         try   
    28.         {   
    29.             var store = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(fileName);   
    30.             return true;   
    31.         }   
    32.         catch   
    33.         {   
    34.             return false;   
    35.         }   
    36.     }   
    37.   
    38.     // Retrieve the specific contact from the database.   
    39.     public Contacts ReadContact(int contactid)   
    40.     {   
    41.         using (var dbConn = new SQLiteConnection(App.DB_PATH))   
    42.         {   
    43.             var existingconact = dbConn.Query<Contacts>("select * from Contacts where Id =" + contactid).FirstOrDefault();   
    44.             return existingconact;   
    45.         }   
    46.     }   
    47.     // Retrieve the all contact list from the database.   
    48.     public ObservableCollection<Contacts> ReadContacts()   
    49.     {   
    50.         using (var dbConn = new SQLiteConnection(App.DB_PATH))   
    51.         {   
    52.             List<Contacts> myCollection  = dbConn.Table<Contacts>().ToList<Contacts>();   
    53.             ObservableCollection<Contacts> ContactsList = new ObservableCollection<Contacts>(myCollection);   
    54.             return ContactsList;   
    55.         }   
    56.     }   
    57.        
    58.     //Update existing conatct   
    59.     public void UpdateContact(Contacts contact)   
    60.     {   
    61.         using (var dbConn = new SQLiteConnection(App.DB_PATH))   
    62.         {   
    63.             var existingconact = dbConn.Query<Contacts>("select * from Contacts where Id =" + contact.Id).FirstOrDefault();   
    64.             if (existingconact != null)   
    65.             {   
    66.                 existingconact.Name = contact.Name;   
    67.                 existingconact.PhoneNumber = contact.PhoneNumber;   
    68.                 existingconact.CreationDate = contact.CreationDate;   
    69.                 dbConn.RunInTransaction(() =>   
    70.                 {   
    71.                     dbConn.Update(existingconact);   
    72.                 });   
    73.             }   
    74.         }   
    75.     }   
    76.     // Insert the new contact in the Contacts table.   
    77.     public void Insert(Contacts newcontact)   
    78.     {   
    79.         using (var dbConn = new SQLiteConnection(App.DB_PATH))   
    80.         {   
    81.             dbConn.RunInTransaction(() =>   
    82.                 {   
    83.                     dbConn.Insert(newcontact);   
    84.                 });   
    85.         }   
    86.     }   
    87.       
    88.     //Delete specific contact   
    89.     public void DeleteContact(int Id)   
    90.     {   
    91.         using (var dbConn = new SQLiteConnection(App.DB_PATH))   
    92.         {   
    93.             var existingconact = dbConn.Query<Contacts>("select * from Contacts where Id =" + Id).FirstOrDefault();   
    94.             if (existingconact != null)   
    95.             {   
    96.                 dbConn.RunInTransaction(() =>   
    97.                 {   
    98.                     dbConn.Delete(existingconact);   
    99.                 });   
    100.             }   
    101.         }   
    102.     }   
    103.     //Delete all contactlist or delete Contacts table   
    104.     public void DeleteAllContact()   
    105.     {   
    106.         using (var dbConn = new SQLiteConnection(App.DB_PATH))   
    107.         {   
    108.             //dbConn.RunInTransaction(() =>   
    109.             //   {   
    110.                    dbConn.DropTable<Contacts>();   
    111.                    dbConn.CreateTable<Contacts>();   
    112.                    dbConn.Dispose();   
    113.                    dbConn.Close();   
    114.                //});   
    115.         }   
    116.     }   
    117. }  

     

3. How to bind SQLite data to listbox

In the preceding Step 2.1, I created a database helper class named "DatabaseHelperClass.cs" that is the main head for this sample to perform all the SQlite operations. Let's first see my project hierarchy like this.

bind SQLite data to listbox

In the app.xaml class let's create a database. In the constructor we check if the database exists and if it does not we create it. Since if no file exists, it will get an exception.

C# Code
  1. public partial class App : Application   
  2. {   
  3.     public static string DB_PATH = Path.Combine(Path.Combine(ApplicationData.Current.LocalFolder.Path, "ContactsManager.sqlite"));//DataBase Name   
  4.     public App()   
  5.     {   
  6.       if (!CheckFileExists("ContactsManager.sqlite").Result)   
  7.       {   
  8.           using (var db = new SQLiteConnection(DB_PATH))   
  9.           {   
  10.               db.CreateTable<Contacts>();   
  11.           }   
  12.       }    
  13. }   
  14.    
  15. private async Task<bool> CheckFileExists(string fileName)   
  16. {   
  17.    try   
  18.    {   
  19.        var store = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(fileName);   
  20.        return true;   
  21.    }   
  22.    catch   
  23.    {   
  24.    }   
  25.    return false;   
  26. }  
Next I divided my project into a MVVM pattern for simplicity. So in the Model folder I placed a table class named "Contacts.cs". In ViewModels, I placed DB helpers classes (DatabaseHelperClass.cs and ReadAllContactsList.cs). And finally in the Views folder I placed all three of my UI related pages.
  • AddConatct.xaml: This page is for adding a contact to the database. When the "Add Contact" button is clicked it will add the contact into the database like this:

    AddConatct

    C# Code
    1. private async void AddContact_Click(object sender, RoutedEventArgs e)   
    2. {   
    3.     DatabaseHelperClass Db_Helper = new DatabaseHelperClass();//Creating object for DatabaseHelperClass.cs from ViewModel/DatabaseHelperClass.cs    
    4.     if (NametxtBx.Text != "" & PhonetxtBx.Text != "")   
    5.     {   
    6.         Db_Helper.Insert(new Contacts(NametxtBx.Text, PhonetxtBx.Text));   
    7.         Frame.Navigate(typeof(ReadContactList));//after add contact redirect to contact listbox page    
    8.     }   
    9.     else   
    10.     {   
    11.         MessageDialog messageDialog = new MessageDialog("Please fill two fields");//Text should not be empty    
    12.         await messageDialog.ShowAsync();   
    13.     }   
    14. }  
  • ReadContactList.xaml: This page is for displaying the entire DB contact list with a listbox. And in this screen there are two buttons (Add Contact and DeleteAll) for correspondingly adding a contact to the DB and to delete the entire table data. First I made the following listbox datatemplate for binding the database contacts.

    XAML
    1. <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">   
    2.       <Grid.RowDefinitions>   
    3.           <RowDefinition Height="auto"/>   
    4.           <RowDefinition Height="*"/>   
    5.       </Grid.RowDefinitions>   
    6.       <StackPanel Width="400" Orientation="Horizontal" Grid.Row="0">   
    7.           <Button  Margin="20,0,0,0" Content="Add Contact"  Click="AddContact_Click"/>   
    8.           <Button Name="Btn_Delete" Margin="100,0,0,0" Content="DeleteAll" Click="DeleteAll_Click"/>   
    9.       </StackPanel>   
    10.       <ListBox Background="Transparent" Margin="6" Height="auto" BorderThickness="2" MaxHeight="580" Grid.Row="1" x:Name="listBoxobj" SelectionChanged="listBoxobj_SelectionChanged">   
    11.           <ListBox.ItemTemplate>   
    12.               <DataTemplate>   
    13.                   <Grid Width="350" >   
    14.                       <Border Margin="5" BorderBrush="White" BorderThickness="1">   
    15.                           <Grid>   
    16.                               <Grid.RowDefinitions>   
    17.                                   <RowDefinition Height="Auto"/>   
    18.                                   <RowDefinition Height="Auto"/>   
    19.                               </Grid.RowDefinitions>   
    20.                               <TextBlock Margin="5,0,0,0" Grid.Row="0" x:Name="NameTxt" TextWrapping="Wrap" Text="{Binding Name}" FontSize="28" Foreground="White"/>   
    21.                               <TextBlock Grid.Row="0" Text=">" FontSize="28"  HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="White"/>   
    22.                               <TextBlock Margin="5,0,0,0" Grid.Row="1" x:Name="PhoneTxt"  TextWrapping="Wrap" Foreground="White" FontSize="18" Text="{Binding PhoneNumber}" />   
    23.                               <TextBlock HorizontalAlignment="Right" Margin="0,0,35,0" Grid.Row="3" x:Name="CreateddateTxt" Foreground="White" FontSize="18" TextWrapping="Wrap" Text="{Binding CreationDate}" />   
    24.                           </Grid>   
    25.                       </Border>   
    26.                   </Grid>   
    27.               </DataTemplate>   
    28.           </ListBox.ItemTemplate>   
    29.       </ListBox>   
    30.   
    31.   </Grid>  
    ReadContactList

    So when the page is loaded, I do the following:

    C# Code
    1. private void ReadContactList_Loaded (object sender, RoutedEventArgs e)   
    2. {   
    3.    ReadAllContactsList dbcontacts = new ReadAllContactsList();   
    4.    DB_ContactList = dbcontacts.GetAllContacts();//Get all DB contacts   
    5.    if (DB_ContactList.Count > 0)   
    6.    {   
    7.       Btn_Delete.IsEnabled = true;   
    8.    }   
    9.    listBoxobj.ItemsSource = DB_ContactList.OrderByDescending(i => i.Id).ToList();//Binding DB data to LISTBOX and Latest contact ID can Display first.   
    10. }  
    When the "Add Contact" button is clicked it navigates to the "AddConatct.xaml" page to add the contact in the DB.

    C# Code
    1. private void AddContact_Click(object sender, RoutedEventArgs e)   
    2. {   
    3.    Frame.Navigate(typeof(AddConatct));   
    4. }  
    For when the "DeleteAll" button is clicked, I did it like this:

    C# Code
    1. private async void DeleteAll_Click(object sender, RoutedEventArgs e)   
    2. {   
    3.     var dialog = new MessageDialog("Are you sure you want to remove all your data ?");   
    4.     dialog.Commands.Add(new UICommand("No"new UICommandInvokedHandler(Command)));   
    5.     dialog.Commands.Add(new UICommand("Yes"new UICommandInvokedHandler(Command)));   
    6.     await dialog.ShowAsync();   
    7. }  
    8.   
    9.   
    10. private void Command(IUICommand command)   
    11. {   
    12.     if (command.Label.Equals("Yes"))   
    13.     {   
    14.         DatabaseHelperClass Db_Helper = new DatabaseHelperClass();   
    15.         Db_Helper.DeleteAllContact();//delete all DB contacts    
    16.         DB_ContactList.Clear();//Clear collections    
    17.         Btn_Delete.IsEnabled = false;   
    18.         listBoxobj.ItemsSource = DB_ContactList;   
    19.     }   
    20. }  
    When a listbox item is selected, I navigate to the "Delete_UpdateContacts.xaml" page to delete/update the corresponding contact details upon the listbox SelectionChanged event like this.

    C# Code
    1. private void listBoxobj_SelectionChanged(object sender, SelectionChangedEventArgs e)   
    2. {   
    3.    int SelectedContactID = 0;   
    4.    if (listBoxobj.SelectedIndex != -1)   
    5.    {   
    6.       Contacts listitem = listBoxobj.SelectedItem as Contacts;//Get slected listbox item contact ID   
    7.       Frame.Navigate(typeof(Delete_UpdateContacts),SelectedContactID=listitem.Id);   
    8.   
    9.    }   
    10. }  
  • Delete_UpdateContacts.xaml: This page is for updating/deleting selected contact details.

    Delete UpdateContacts

    See in the preceding, when the listbox item is selected, I passed the selected contact Id as the query string, So in this I get that id in the "OnNavigatedTo" method like this.

    C# Code
    1. protected override void OnNavigatedTo(NavigationEventArgs e)   
    2. {   
    3.    Selected_ContactId = int.Parse(e.Parameter.ToString());   
    4.    currentcontact = Db_Helper.ReadContact(Selected_ContactId);//Read selected DB contact   
    5.    NametxtBx.Text = currentcontact.Name;//get contact Name   
    6.    PhonetxtBx.Text = currentcontact.PhoneNumber;//get contact PhoneNumber   
    7. }  
    When the "Delete" button is pressed I do it like this.

    C# Code
    1. private void DeleteContact_Click(object sender, RoutedEventArgs e)   
    2. {   
    3.    Db_Helper.DeleteContact(Selected_ContactId);//Delete selected DB contact Id.   
    4.    Frame.Navigate(typeof(ReadContactList));   
    5. }  
    When the "Update" button is pressed I do it like this.

    C# Code
    1. private void UpdateContact_Click(object sender, RoutedEventArgs e)   
    2. {   
    3.    currentcontact.Name = NametxtBx.Text;   
    4.    currentcontact.PhoneNumber = PhonetxtBx.Text;   
    5.    Db_Helper.UpdateContact(currentcontact);//Update selected DB contact Id   
    6.    Frame.Navigate(typeof(ReadContactList));   
    7. }  
4. How to explore my SQLite database data

The Isolated Storage Explorer tool gets the database file. This tool is installed under the folder path Program Files (x86)\Microsoft SDKs\Windows Phone\v8.1\Tools\IsolatedStorageExplorerTool.

To use the Isolated Storage Explorer, the following things must be true:
  • The app that you want to test must be installed on the emulator or device.

  • The emulator or device must be running, but the app doesn't have to be running.

You cannot do the following things with the Isolated Storage Explorer:

  • You can't view isolated storage for apps that you've installed from the Windows Phone Store.

  • You can't view app settings that are stored in the local folder in the Isolated Storage Explorer. These are settings that the app has saved using the IsolatedStorageSettings class.

Then execute the following command from the command prompt.

  1. First change the command prompt directory path to Program Files (x86)\Microsoft SDKs\Windows Phone\v8.1\Tools\IsolatedStorageExplorerTool.

    IsolatedStorageExplorerTool

  2. Get the Product Id from the project Package.appxmanifest file in the Packaging Tab under the Package name attribute (in other words 9f68177c-0add-437b-8b43-95ec429ee5b5).

  3. If your app is run in the emulator execute this command: ISETool.exe ts xd 9f68177c-0add-437b-8b43-95ec429ee5b5 c:\data\myfiles.

    emulator execute

  4. If your app is run on the device execute this command: ISETool.exe ts de 9f68177c-0add-437b-8b43-95ec429ee5b5 c:\data\myfiles.

Now the DB content can be found in your computer at c:\data\myfiles like this.

found DB content

Note: This content might change in the future.

Summary:

In this article, we saw the basics of SQLite, how to install the engine, the library SQLite-net and saw the most common operations (also known as code first), such as inserting, updating and deleting data from a table of a database.

This article is also available at my original blog.