Introduction
In my previous article, I gave a tutorial on how we can use Xamarin.iOS (formally known as Monotouch) to build iOS mobile applications using C#. In this blog post, I will introduce a third party library that can aid your mobile application development: sqlite-net.
Introducing sqlite-net (ORM)
The sqlite-net library provides simple, easy-to-use object relation mapping for the SQLite database. The API was designed specifically for mobile applications written in the .NET platform. The library is a single C# source file that is imported into your project with no additional dependences. Database operations can either be synchronous and asynchronous.
Table and Column Definitions
To define your tables, sqlite-net uses attributes on the domain model’s public
properties. The minimal required for defining a table is the PrimaryKey
attribute. The preferred data type for the primary key is an integer. By default, the table and column names will use the class and properties from the domain model for their names.
Let’s look at an example domain:
using SQLite;
namespace Com.Khs.CommandRef.Model
{
[Table("category")]
public class Category
{
[PrimaryKey]
public long Id { get; set; }
public string Description { get; set; }
}
}
When defining the model, the C# data types that sqlite-net supports are Integers, Booleans, Enums, Singles, Doubles, Strings, and DateTime. Here are a list of database attributes that define your table and columns:
Table
– Defines a specific name for the table
Column
– Defines a specific name for the column
PrimaryKey
– Defines the primary key for the table
AutoIncrement
– Guarantees the primary key as having a unique id value. The domain model property should be an integer.
Indexed
– Defines the column as an index
Ignore
– Does not add the class property as a column in the table
Initialize Database
When the iOS application begins to load, I create a database connection and initialize the tables during the FinishedLaunching
method from the AppDelegate
class. First, create the connection to the database using the SQLiteConnection
or SQLiteAsyncConnection
method. The CreateTable
or CreateAsyncTable
method will create a new table for the connection if it does not already exist in the database. The Connection
property will be used by the application for accessing the database.
using SQLite;
namespace Com.Khs.CommandRef
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
public SQLiteConnection Connection { get; private set; }
public override bool FinishedLaunching (UIApplication application, NSDictionary launcOptions)
{
InitializeDatabase();
return true;
}
protected void InitializeDatabase ()
{
Connection = new SQLiteConnection(DbName);
Connection = new SQLiteAsyncConnection(DbName);
Connection.CreateTable<Category>();
Connection.CreateTable<Reference>();
Connection.CreateTable<User>();
Connection.CreateTable<Command>();
}
public string DbName
{
get { return Path.Combine(Environment.GetFolderPath
(Environment.SpecialFolder.Personal), "commandref.db"); }
}
}
For the remainder of the blog, I will constrain my examples using only the synchronous database methods. If you want asynchronous operations, use the corresponding ‘Async
’ method names. (As an example: using InsertAsync
instead of Insert
.)
CRUD Operations
Now that we have the connection created and tables initialized, we can now do some CRUD operations on the database.
Inserting data into your database is as simple as creating a new model object and calling either the Insert
or InsertOrReplace
method. The InsertOrReplace
method will first delete the existing record if it exists, and then insert the new record. If the AutoIncrement
is set on a primary key, the model will return with the new ID.
public void AddCategory(SQLiteConnection db)
{
var category = new Category { Description = "Test" };
var rowsAdded = Db.Insert(category);
Console.WriteLine("SQLite Insert - Rows Added;" + rowsAdded);
List<Category> categories = new List<Category>();
for ( int i = 0; i < 5; i++)
{
categories.Add( new Category { Description = "Test " + i });
}
rowsAdded = Db.InsertAll(categories);
Console.WriteLine("SQLite Insert - Rows Added;" + rowsAdded);
}
The operations for update
and delete
work in similar way as the insert
operation:
public void DeleteCategory(SQLiteCommand db, Category category)
{
var rowsDeleted = Db.Delete<Category>(category);
Console.WriteLine("SQLite Delete - Rows Deleted: " + rowsDeleted);
rowsDeleted = Db.DeleteAll<Category>();
}
public void UpdateCategory(SQLiteCommand db, Category category, List<Category> categories)
{
var rowsUpdated = Db.Update(category);
Console.WriteLine("SQLite Update - Rows Updated: " + rowsUpdated);
rowsUpdated = Db.UpdateAll(categories);
Console.WriteLine("SQLite Update - Rows Updated: " + rowsUpdated);
}
There are two options for querying the database, using predicates or low-level queries. When using the predicates option, the Table
method is used. Additional predicates such as Where
and OrderBy
can be used to tailor the queries.
Let’s look at some examples:
public void QueryCategory(SQLiteCommand db)
{
var categories = Db.Table<Category>().OrderBy(c => c.Description);
var category = Db.Table<Category>().Where
(c => c.Description.Equals("Test"));
categories = Db.Query<Category>
("select * from category where Description = ?", "Test");
}
To simplify the query statements, sqlite-net provides Find
and Get
methods. They will return single object matching the predicate. In the previous example, the query could have been written in the following way:
category = Db.Find(c => c.Description.Equals("Test"));
Additional Features
The sqlite-net also provides a simple transaction framework.
BeginTransaction
– Starts a new database transaction. Throws exception when a transaction is already started.
SaveTransactionPoint
– If a transaction is not started, then a new transaction will be created. Otherwise, set a new rollback point. The database will rollback to the last saved transaction point.
Commit
– Commits the current transaction.
Rollback
– Completely rolls back the current transaction.
RollbackTo
– Rollback to an existing save point set by the SaveTransactionPoint
.
public void TransactionOperation()
{
Db.BeginTransaction( () => {
});
Db.BeginTransaction();
if ( Db.IsInTransaction )
{
Db.Commit();
}
}
This article shows some of the capabilities of the sqlite-net library. If you would like to learn more about the sqlite-net, check it out on Github and see the code, examples, and wiki for more information. Good luck!
– Mark Fricke, asktheteam@keyholesoftware.com