0% found this document useful (0 votes)
38 views8 pages

.NET MAUI SQLite Database Guide

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
38 views8 pages

.NET MAUI SQLite Database Guide

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

7/6/24, 11:53 AM .NET MAUI local databases - .

NET MAUI | Microsoft Learn

.NET MAUI local databases


Article • 01/19/2024

Browse the sample

The SQLite database engine allows .NET Multi-platform App UI (.NET MAUI) apps to load
and save data objects in shared code. You can integrate [Link] into .NET MAUI apps,
to store and retrieve information in a local database, by following these steps:

1. Install the NuGet package.


2. Configure constants.
3. Create a database access class.
4. Access data.
5. Advanced configuration.

This article uses the sqlite-net-pcl NuGet package to provide SQLite database access to a
table to store todo items. An alternative is to use the [Link] NuGet package,
which is a lightweight [Link] provider for SQLite. [Link] implements the
common [Link] abstractions for functionality such as connections, commands, and data
readers.

Install the SQLite NuGet package


Use the NuGet package manager to search for the sqlite-net-pcl package and add the
latest version to your .NET MAUI app project.

There are a number of NuGet packages with similar names. The correct package has these
attributes:

ID: sqlite-net-pcl
Authors: SQLite-net
Owners: praeclarum
NuGet link: sqlite-net-pcl

Despite the package name, use the sqlite-net-pcl NuGet package in .NET MAUI projects.

) Important

[Link] 1/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn

[Link] is a third-party library that's supported from the praeclarum/sqlite-net


repo .

Install SQLitePCLRaw.bundle_green
In addition to sqlite-net-pcl, you temporarily need to install the underlying dependency
that exposes SQLite on each platform:

ID: SQLitePCLRaw.bundle_green
Version: >= 2.1.0
Authors: Eric Sink
Owners: Eric Sink
NuGet link: SQLitePCLRaw.bundle_green

Configure app constants


Configuration data, such as database filename and path, can be stored as constants in your
app. The sample project includes a [Link] file that provides common configuration
data:

C#

public static class Constants


{
public const string DatabaseFilename = "TodoSQLite.db3";

public const [Link] Flags =


// open the database in read/write mode
[Link] |
// create the database if it doesn't exist
[Link] |
// enable multi-threaded database access
[Link];

public static string DatabasePath =>


[Link]([Link], DatabaseFilename);
}

In this example, the constants file specifies default SQLiteOpenFlag enum values that are
used to initialize the database connection. The SQLiteOpenFlag enum supports these
values:

[Link] 2/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn

Create : The connection will automatically create the database file if it doesn't exist.
FullMutex : The connection is opened in serialized threading mode.

NoMutex : The connection is opened in multi-threading mode.


PrivateCache : The connection will not participate in the shared cache, even if it's

enabled.
ReadWrite : The connection can read and write data.
SharedCache : The connection will participate in the shared cache, if it's enabled.

ProtectionComplete : The file is encrypted and inaccessible while the device is locked.
ProtectionCompleteUnlessOpen : The file is encrypted until it's opened but is then

accessible even if the user locks the device.


ProtectionCompleteUntilFirstUserAuthentication : The file is encrypted until after the

user has booted and unlocked the device.


ProtectionNone : The database file isn't encrypted.

You may need to specify different flags depending on how your database will be used. For
more information about SQLiteOpenFlags , see Opening A New Database Connection on
[Link].

Create a database access class


A database wrapper class abstracts the data access layer from the rest of the app. This class
centralizes query logic and simplifies the management of database initialization, making it
easier to refactor or expand data operations as the app grows. The sample app defines a
TodoItemDatabase class for this purpose.

Lazy initialization
The TodoItemDatabase uses asynchronous lazy initialization to delay initialization of the
database until it's first accessed, with a simple Init method that gets called by each
method in the class:

C#

public class TodoItemDatabase


{
SQLiteAsyncConnection Database;

public TodoItemDatabase()
{
[Link] 3/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn
}

async Task Init()


{
if (Database is not null)
return;

Database = new SQLiteAsyncConnection([Link],


[Link]);
var result = await [Link]<TodoItem>();
}
...
}

Data manipulation methods


The TodoItemDatabase class includes methods for the four types of data manipulation:
create, read, edit, and delete. The [Link] library provides a simple Object Relational
Map (ORM) that allows you to store and retrieve objects without writing SQL statements.

The following example shows the data manipulation methods in the sample app:

C#

public class TodoItemDatabase


{
...
public async Task<List<TodoItem>> GetItemsAsync()
{
await Init();
return await [Link]<TodoItem>().ToListAsync();
}

public async Task<List<TodoItem>> GetItemsNotDoneAsync()


{
await Init();
return await [Link]<TodoItem>().Where(t =>
[Link]).ToListAsync();

// SQL queries are also possible


//return await [Link]<TodoItem>("SELECT * FROM [TodoItem]
WHERE [Done] = 0");
}

public async Task<TodoItem> GetItemAsync(int id)


{
await Init();

[Link] 4/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn
return await [Link]<TodoItem>().Where(i => [Link] ==
id).FirstOrDefaultAsync();
}

public async Task<int> SaveItemAsync(TodoItem item)


{
await Init();
if ([Link] != 0)
return await [Link](item);
else
return await [Link](item);
}

public async Task<int> DeleteItemAsync(TodoItem item)


{
await Init();
return await [Link](item);
}
}

Access data
The TodoItemDatabase class can be registered as a singleton that can be used throughout
the app if you are using dependency injection. For example, you can register your pages
and the database access class as services on the IServiceCollection object, in
[Link], with the AddSingleton and AddTransient methods:

C#

[Link]<TodoListPage>();
[Link]<TodoItemPage>();

[Link]<TodoItemDatabase>();

These services can then be automatically injected into class constructors, and accessed:

C#

TodoItemDatabase database;

public TodoItemPage(TodoItemDatabase todoItemDatabase)


{
InitializeComponent();
database = todoItemDatabase;
}

[Link] 5/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn

async void OnSaveClicked(object sender, EventArgs e)


{
if ([Link]([Link]))
{
await DisplayAlert("Name Required", "Please enter a name for the todo
item.", "OK");
return;
}

await [Link](Item);
await [Link]("..");
}

Alternatively, new instances of the database access class can be created:

C#

TodoItemDatabase database;

public TodoItemPage()
{
InitializeComponent();
database = new TodoItemDatabase();
}

For more information about dependency injection in .NET MAUI apps, see Dependency
injection.

Advanced configuration
SQLite provides a robust API with more features than are covered in this article and the
sample app. The following sections cover features that are important for scalability.

For more information, see SQLite Documentation on [Link].

Write-ahead logging
By default, SQLite uses a traditional rollback journal. A copy of the unchanged database
content is written into a separate rollback file, then the changes are written directly to the
database file. The COMMIT occurs when the rollback journal is deleted.

[Link] 6/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn

Write-Ahead Logging (WAL) writes changes into a separate WAL file first. In WAL mode, a
COMMIT is a special record, appended to the WAL file, which allows multiple transactions
to occur in a single WAL file. A WAL file is merged back into the database file in a special
operation called a checkpoint.

WAL can be faster for local databases because readers and writers do not block each other,
allowing read and write operations to be concurrent. However, WAL mode doesn't allow
changes to the page size, adds additional file associations to the database, and adds the
extra checkpointing operation.

To enable WAL in [Link], call the EnableWriteAheadLoggingAsync method on the


SQLiteAsyncConnection instance:

C#

await [Link]();

For more information, see SQLite Write-Ahead Logging on [Link].

Copy a database
There are several cases where it may be necessary to copy a SQLite database:

A database has shipped with your application but must be copied or moved to
writeable storage on the mobile device.
You need to make a backup or copy of the database.
You need to version, move, or rename the database file.

In general, moving, renaming, or copying a database file is the same process as any other
file type with a few additional considerations:

All database connections should be closed before attempting to move the database
file.
If you use Write-Ahead Logging, SQLite will create a Shared Memory Access (.shm)
file and a (Write Ahead Log) (.wal) file. Ensure that you apply any changes to these
files as well.

[Link] 7/8
7/6/24, 11:53 AM .NET MAUI local databases - .NET MAUI | Microsoft Learn

6 Collaborate with us on
GitHub .NET MAUI feedback
.NET MAUI is an open source project.
The source for this content can
Select a link to provide feedback:
be found on GitHub, where you
can also create and review issues
 Open a documentation issue
and pull requests. For more
information, see our contributor
 Provide product feedback
guide.

[Link] 8/8

Common questions

Powered by AI

The sqlite-net-pcl package facilitates Object Relational Mapping (ORM) in .NET MAUI applications by allowing developers to manage database operations through abstractions, thus eliminating the need to write raw SQL statements. This package provides a simple ORM that lets developers store and retrieve .NET objects mapping them to database tables and operations, such as CRUD, using object-oriented code. This increases the application's maintainability and readability by keeping data logic consistent with the app's code structure .

The main advantage of using Write-Ahead Logging (WAL) in SQLite for .NET MAUI apps is the improved performance gained through concurrent read and write operations, as it allows transactions to occur without blocking. Another benefit is the enhanced durability of transactions since changes are committed to the WAL before being applied to the database file. However, WAL does not support changes to the page size and adds complexity with additional files like the WAL and Shared Memory Access (.shm) files that must be managed. Furthermore, it requires periodic checkpoints to merge changes back into the main database, which can add overhead .

Implementing dependency injection for database access in .NET MAUI involves registering database access classes and app pages as services within the application's service collection. This allows for instances to be automatically injected into class constructors, reducing coupling and increasing modularity. For instance, the TodoItemDatabase class can be registered as a singleton, ensuring a single instance is used throughout the application, while app pages can be registered as transient. This design pattern enhances testability, as dependencies can be mocked or swapped easily during testing .

SQLiteOpenFlags are configuration options used to initialize a database connection, impacting both security and accessibility. For instance, using the ProtectionComplete flag encrypts the database file, making it inaccessible while the device is locked. Meanwhile, the ProtectionCompleteUnlessOpen flag allows the file to be accessible if the user locks the device after it has been opened. These flags ensure the database's confidentiality in scenarios like device theft or unauthorized access. Other flags like ReadWrite specify the database's open mode and enable features such as multi-threading using the SharedCache flag .

A developer might create a wrapper class for a SQLite database in a .NET MAUI app to abstract the data access logic from the rest of the application, centralizing database operations. This encapsulation allows changes or extensions to the data layer without impacting other parts of the app, enhancing maintainability. Additionally, it improves consistency and testability, as database operations can be mocked or replaced without affecting the codebase dependent on these operations. The TodoItemDatabase class is an example that manages CRUD operations with asynchronous lazy initialization for efficient resource management .

An alternative to the sqlite-net-pcl package for SQLite database integration in .NET MAUI is the Microsoft.Data.Sqlite package. This package is a lightweight ADO.NET provider for SQLite, implementing common ADO.NET abstractions such as connections, commands, and data readers. It offers a more traditional approach to database access, closely resembling standard ADO.NET practices, compared to sqlite-net-pcl's simplified ORM model. Developers can choose based on their familiarity with ADO.NET or their preference for a higher-level ORM abstraction .

Write-ahead logging (WAL) enhances performance by allowing concurrent read/write operations without locking. In WAL mode, changes are first written to a separate WAL file instead of the database file. Multiple transactions can occur within a single WAL file, and the changes are later merged into the database during a checkpoint operation. This design reduces conflicts between readers and writers, thus improving the performance of local databases in .NET MAUI applications. However, it introduces additional complexities, such as the need for checkpointing and additional file management .

Integrating a SQLite database into a .NET MAUI app involves several steps. First, install the sqlite-net-pcl NuGet package to provide SQLite database access. Next, you need to configure constants such as the database filename and path, which can be stored as constants in your app. Then, create a database access class, which typically abstracts the data access layer and uses asynchronous lazy initialization to delay initialization until the database is first accessed. Finally, define methods for data manipulation like create, read, update, and delete (CRUD operations). These methods utilize the SQLite.NET library's Object Relational Map (ORM) to allow you to handle database objects without directly writing SQL statements .

Lazy initialization delays the creation of the Database connection instance until it is needed for the first time. This approach conserves resources by not establishing connections or loading data unless required, which can improve the application's performance. In a .NET MAUI app, this means that the database access class, such as TodoItemDatabase, initializes its connection only when one of its methods is invoked. This ensures that resources are utilized efficiently and only when necessary .

Before moving or copying a SQLite database file in a .NET MAUI application, it is crucial to ensure all database connections are closed to avoid data corruption. If write-ahead logging (WAL) is used, the associated .wal and .shm files need to be moved or copied alongside the database file. This is because they contain changes and metadata essential for the database integrity and functionality. Failure to include these files could result in incomplete transactions or database errors .

You might also like