Almacenamiento de datos de forma local con SQLite

Completado

SQLite es útil cuando tiene datos relacionales. Supongamos que está creando una aplicación de redes sociales. Debe almacenar información sobre los suscriptores a la aplicación. Estos datos incluyen su nombre y un Id. único para cada usuario. Puede modelar fácilmente este tipo de relación en una base de datos SQLite.

En esta unidad, aprenderá a usar SQLite en una aplicación MAUI de .NET mediante SQLite-net.

¿Qué es SQLite?

SQLite es una base de datos local multiplataforma ligera que es un estándar del sector para aplicaciones móviles. SQLite no requiere un servidor. La base de datos se almacena en un único archivo de disco en el sistema de archivos del dispositivo. Todas las operaciones de lectura y escritura se realizan directamente en el archivo de disco de SQLite.

Las bibliotecas nativas de SQLite están integradas en iOS y Android de forma predeterminada, pero el motor solo admite una API de C/C++. Este escenario no es ideal para desarrolladores de .NET, que buscan una manera de que SQLite y .NET interactúen.

¿Qué es SQLite-net?

Hay varios contenedores de C# en torno al motor de SQLite nativo que los desarrolladores de .NET pueden usar. Muchos desarrolladores de .NET usan un popular contenedor C# denominado SQLite-net.

SQLite-net es un asignador relacional de objetos. Ayuda a simplificar el proceso de definición de esquemas de base de datos al permitirle usar los modelos definidos en sus proyectos para que sirvan como esquema.

Diagrama que muestra cómo SQLite-NET proporciona un contenedor .NET y el motor de SQLite C/C++.

Por ejemplo, considere la clase siguiente que modela un User:

class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    ...
}

Mediante un asignador relacional de objetos, puede tomar esta clase User inicial y crear una tabla de base de datos denominada User que tenga columnas para los campos Id y Username de esta clase.

SQLite-net se envía como un paquete de NuGet. Debe agregar el paquete sqlite-net-pcl a las aplicaciones para usarlo.

Cómo conectar con una base de datos de SQLite

Puede establecer una conexión a una base de datos SQLite desde una aplicación a través de un objeto SQLiteConnection. Esta clase se define en el espacio de nombres SQLite, junto con los otros tipos y métodos que proporciona SQLite. Al crear una instancia de este objeto, pasa el nombre del archivo de base de datos. A continuación, el constructor abre el archivo si existe o lo crea si no está presente.

El código siguiente muestra un ejemplo:

using SQLite;
...
string filename = ...
SQLiteConnection conn = new SQLiteConnection(filename);

Recuerde que el filename debe apuntar a una ubicación en el espacio aislado de la aplicación.

Procedimientos para crear una tabla

Recuerde que SQLite-NET es un asignador relacional de objetos, lo que significa que puede compilar el esquema de la base de datos desde clases de C#. SQLite-net puede crear una tabla de base de datos a partir de una clase C# normal, pero hay muchos atributos que se pueden agregar a una clase para proporcionar más metadatos. Estos metadatos ayudan a SQLite a imponer características como la singularidad y a aplicar restricciones a los datos.

Los atributos disponibles incluyen:

  • Table: especifique el nombre de la tabla si quiere que sea diferente del nombre de la clase.
  • PrimaryKey: especifique que una columna es la clave principal.
  • AutoIncrement: especifique que una columna debe aumentar automáticamente de valor cuando se inserta una nueva fila.
  • Column: especifique el nombre de una columna si quiere que sea diferente del nombre de la propiedad.
  • MaxLength: especifique el número máximo de caracteres que se pueden usar en la columna.
  • Unique: especifique que el valor de la columna debe ser único entre todas las demás filas.

El código siguiente muestra una versión actualizada de la clase User que aplica estos atributos:

[Table("user")]
public class User
{
    // PrimaryKey is typically numeric 
    [PrimaryKey, AutoIncrement, Column("_id")]
    public int Id { get; set; }

    [MaxLength(250), Unique]
    public string Username { get; set; }
    ...
}

Después de definir la clase C#, llame al método genérico CreateTable de la clase SQLiteConnection para generar la tabla en la base de datos. Especifique la clase como el parámetro tipo. Este es un ejemplo:

SQLiteConnection conn = new SQLiteConnection(filename);
conn.CreateTable<User>();

Si la tabla ya existe en la base de datos, el método CreateTable comprueba el esquema para ver si hay cambios. En caso afirmativo, la operación intenta actualizar el esquema de la base de datos.

Cómo realizar operaciones básicas de lectura y escritura

Después de crear la tabla, puede empezar a interactuar con ella. Para agregar una fila, use el método Insert en la instancia SQLiteConnection y proporcione un objeto del tipo adecuado que contenga los datos que se van a insertar. El código siguiente muestra cómo agregar una fila nueva a la tabla User:

public int AddNewUser(User user)
{
    int result = conn.Insert(user);
    return result;
}

El método Insert devuelve un int, que representa el número de filas insertadas en la tabla. En este caso, dicho número es uno.

Para recuperar filas de una tabla, use el método Table. Este método devuelve una colección de objetos (que puede estar vacío):

public List<User> GetAllUsers()
{
    List<User> users = conn.Table<User>().ToList();
    return users;
}

El método Table devuelve un objeto TableQuery\<T>. Para obtener una List, use el método ToList, tal como se muestra en el ejemplo anterior.

Ejecución de una consulta de SQLite mediante LINQ

El método Table recupera todas las filas de una tabla. En la mayoría de los casos, desea devolver solo un subconjunto de las filas que coinciden con un conjunto de criterios especificados. Para estas tareas, use LINQ con SQLite-net.

SQLite-net admite muchas consultas LINQ comunes, entre las que se incluyen:

  • Where
  • Take
  • Skip
  • OrderBy
  • OrderByDescending
  • ThenBy
  • ElementAt
  • First
  • FirstOrDefault
  • ThenByDescending
  • Count

Con estos métodos, puede usar la sintaxis de método de extensión o la sintaxis de C# de LINQ. Por ejemplo, este es un fragmento de código que le permite recuperar los detalles de un usuario especificado:

public User GetByUsername(string username)
{
    var user = from u in conn.Table<User>()
               where u.Username == username
               select u;
    return user.FirstOrDefault();
}

Actualizar y eliminar filas

Se actualiza una fila mediante el método Update del objeto SQLiteConnection. Proporcione un objeto que define la fila que se va a actualizar con sus nuevos valores. El método Update modifica la fila que tiene el mismo valor de clave principal que el objeto proporcionado. El valor devuelto es el número de filas modificadas: Si este valor es cero, significa que no se encontraron filas con una clave principal coincidente y no se actualizó nada. El siguiente fragmento de código muestra este método en acción:

public int UpdateUser(User user)
{
    int result = 0;
    result = conn.Update(user);
    return result;
}

Quite filas de una tabla con el método SQLiteConnection del objeto Delete. La forma más sencilla de este método toma la clave principal del elemento que se va a eliminar como parámetro, como se muestra en el ejemplo siguiente. Esta forma del método Delete es genérica y requiere un parámetro de tipo. El valor devuelto es el número de filas quitadas de la tabla:

public int DeleteUser(int userID)
{
    int result = 0;
    result = conn.Delete<User>(userID);
    return result;
}