Adding SQLite to my Xamarin forms application

To be totally honest, this post Xamarin.Forms Local Databases covers everything you need to know.

Simply add Frank Krueger’s NuGet package to your shared code project. This library is both a database access library and ORM.

We’ll need to create the database file, hence we can create our file location using the following

private static readonly string DatabaseLocation =
   Path.Combine(
      Environment.GetFolderPath
        (Environment.SpecialFolder.LocalApplicationData), 
        "Capture.db3");

Create the database

var database = new SQLiteAsyncConnection(DatabaseLocation);
await database.CreateTableAsync<DataItem>();

Depending on the use case it may be best to create the database connection when the application starts and keep available whilst the application is running. In this instance my calls to the DB are going to be dictated by the user, i.e. pressing a button, so we can create the connection, then create a table for our data objects.

Note: The data object stored into the database must have a default constructor and not be abstract etc. for it to work with the ORM part of this library.

Closing the database

The database connection does not support the IDisposable interface, so we need to explicitly call

await database.CloseAsync();

Note: I’ve not checked the source for the library and had no issues with not closing the connection.

Inserting items into the database

We can insert new items into the database using

await database.InsertAsync(dataItem);

// or a batch insert using 

await database.InsertAllAsync(dataItems)

// or an insert OR replace using

await database.InsertOrReplaceAsync(dataItem)

Updating rows

We saw that we can InsertOrReplace rows but this is based upon whether the object is unique. In other words the data object is first inserted and then a key returned, if another object matches this newly inserted one, then it’s deleted.

We can call UpdateAsync if we know a data object has already been saved to the database and we just want to update it, i.e.

await database.UpdateAsync(dataItem);

and thus if we’re tracking, within our data object whether it’s been saved and decide whether to update or insert using

if(dataItem.Id != 0)
{
   await database.UpdateAsync(dataItem);
}
else
{
   dataItem.Id = await database.InsertAsync(dataItem);
}

Querying the database

It wouldn’t be much of a database if we couldn’t run queries on it. We can use

var list = 
   await database.QueryAsync<DataItem>(
      "SELECT * FROM [DataItem] WHERE [Success] = 0"
   );

We can also use Linq like this

var dataItem = 
   database.Table<DataItem>()
      .Where(i => i.Name == "Samsung").ToListAsync();

Hence here we’ll get a list of all DataItems with the name “Samsung”.

Deleting data

We can use

await database.DeleteAsync(dataItem);

Deleting the database

As the database is stored as a file we can simply delete the file from the file system using

if (File.Exists(DatabaseLocation))
{
   File.Delete(DatabaseLocation);
}

More on our data objects

The only thing we’ve specified in any of the above code, for our data objects, is that they must have a default constructor on a concrete class, but as this SQLite NuGet package is acting like an ORM (as opposed to us creating our tables etc. in SQL), we’ll probably need some of the following properties added to our data object…

In the above we’ve showed that we can get a key back from an insert etc. but we can also add a key to the data objects themselves and have SQLite supply the keys. So for example we can add the following to our data item class

[PrimaryKey, AutoIncrement]
public int Id { get; set; }

Now the id is our primary key and is automatically supplied during an insert using an AutoIncrement algorithm.

We can also add indexed properties, for example

[Indexed]
public string Name { get; set; }

We can ignore properties by marking them with the IgnoreAttribute, i.e.

[Ignore]
public int AverageDb { get; set; }

Other attributes, include the following UniqueAttribute, MaxLengthAttribute , NotNullAttribute, StoreAsTextAttribute (for enums) and CollationAttribute (BINARY, NOCASE, RTRIM are supported with BINARY being the default) for comparisons.