Xamarin.Forms: Creando una BBDD con Entity Framework Core SQLite

El hecho de utilizar almacenamiento de datos local en nuestras aplicaciones móviles es cada vez más común. Probablemente en más de una ocasión habéis tenido este requerimiento para algunos de vuestros desarrollos. Hoy queremos compartir con vosotros cómo hacerlo con Entity Framework Core SQLite.

En este post, desarrollaremos una aplicación simple para poder listar los datos, actualizarlos, borrarlos y darlos de alta en la base de datos que crearemos.

Para poder utilizar Entity Framework Core lo primero de todo es añadir el paquete Microsoft.EntityFrameworkCore.Sqlite a los proyectos de nuestra solución:

Además en iOS, tendremos que añadir la siguiente línea de código en AppDelegate.cs antes de inicializar Xamarin.Forms:

______

SQLitePCL.Batteries_V2.Init();

Ahora especificaremos la ruta de nuestra BBDD. Esto requiere de implementación por plataforma:

iOS:

______

    public class DatabaseService: IDatabaseService
    {
        public string GetDbPath()
        {
            return Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                DbConstants.DB_NAME);
        }
    }

Android:

______

    public class DatabaseService : IDatabaseService
    {
        public string GetDbPath()
        {
            return Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.Personal),
                DbConstants.DB_NAME);
        }
    }

En nuestra PCL, crearemos una clase que herede de DbContext en la que indicaremos la ruta física donde se alojará nuestra base de datos sobrescribiendo el método OnConfiguring:

______

    public class DataBaseContext: DbContext
    {
        private IDatabaseService DataBaseService => DependencyService.Get();

 

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite($"Filename={DataBaseService.GetDbPath()}");
        }
    }

Una vez definida la ruta, crearemos el esquema de nuestra BBDD. En nuestro caso, sólo tendremos dos tablas: Pacient.cs y Doctor.cs. Nuestra aplicación gestionará pacientes pudiendo darlos de alta, eliminarlos o actualizar sus datos.

______
    
    public class Patient: BaseModel
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public int? Age { get; set; }
        public string PatientId { get; set; }


        public int? DoctorId { get; set; }
        public Doctor Doctor { get; set; }
    }

    public class Doctor: BaseModel
    {
        public string CompleteName { get; set; }


        public ICollection Patients { get; set; }
    }




A continuación, indicaremos a nuestro DbContext cuáles son las tablas de la BBDD en la clase DatabaseContext.cs de la siguiente forma:

______

    public DbSet Patients { get; set; }
        public DbSet Doctors { get; set; }


Expondremos también una propiedad para poder acceder al contexto. Para ello nuestra clase DatabaseContext.cs heredará de una nueva interfaz llamada IDbContext, la cuál contendrá dicha propiedad implementándola en DatabaseContext.cs:

______

    public interface IDbContext
    {
        DataBaseContext DbContext { get; }
    }

    
    public class DataBaseContext: DbContext, IDbContext
    {
        private IDatabaseService DataBaseService => DependencyService.Get();


        DataBaseContext _dbContext;
        DataBaseContext IDbContext.DbContext
        {
            get
            {
                if (_dbContext == null)
                {
                    _dbContext = new DataBaseContext();
                    _dbContext.Database.EnsureCreated();
                }
                return _dbContext;
            }
        }




Con nuestro esquema de datos ya preparado, podemos comenzar a crear nuestra capa de acceso a datos. Crearemos la clase LocalDataBaseService.cs dónde implementaremos las consultas a BBDD de forma genérica para todas las entidades existentes en la misma:

______
    public class LocalDataBaseService : ILocalDataBaseService
        where T: BaseModel
    {
        private IDbContext DbAccessService => DependencyService.Get();
        protected DataBaseContext DbContext => DbAccessService.DbContext;
        protected DbSet DbSet => DbContext.Set();

 


        public async Task GetAllAsync()
        {
            return await DbSet.ToListAsync();
        }

 

        public  async Task GetByIdAsync(int id)
        {
            return await DbSet.FindAsync(id);
        }

 

        public async Task AddAsync(T entity)
        {
            await DbSet.AddAsync(entity);
            await DbContext.SaveChangesAsync();
            return entity;
        }

 

        public async Task UpdateAsync(T entity)
        {
            DbSet.Update(entity);
            await DbContext.SaveChangesAsync();
            return entity;
        }

 

        public async Task DeleteAsync(int id)
        {
            var entity = await GetByIdAsync(id);
            DbSet.Remove(entity);
            await DbContext.SaveChangesAsync();
            return entity;
        }

 

        public async Task AddRangeAsync(List entities)
        {
            await DbSet.AddRangeAsync(entities);
            await DbContext.SaveChangesAsync();
        }
    }

Ya tenemos nuestro código listo para comenzar a añadir información a nuestra base de datos llamando a estos métodos desde los ViewModels:

En nuestra aplicación tendremos una primera pantalla para poder visualizar todos los pacientes dados de alta.

Estos datos se pueden obtener como se muestra a continuación llamando al  método GetAllAsync() del servicio que acabamos de crear:

______

protected ILocalDataBaseService PatientsService => DependencyService.Get<ILocalDataBaseService>();

______

var patients = await PatientsService.GetAllAsync();

Desde la vista anterior pulsando en el “+” se navega a la pantalla en la que se pueden dar de alta nuevos pacientes:

______

    await PatientsService.AddAsync(Patient);


Desde la vista principal, también se puede acceder al detalle del paciente para visualizar toda su información:

______

    Patient = await PatientsService.GetByIdAsync(id);



En el detalle es posible actualizar los datos del paciente o eliminar al mismo mediante los siguientes comandos:

______

        async Task OnDeletePatient()
        {
            await ExecuteAsync(async () =>
            {
                await PatientsService.DeleteAsync(Patient.Id);
                await Navigation.PopAsync();
            });
        }


______

        async Task OnUpdatePatient()
        {
            await ExecuteAsync(async () =>
            {
                await PatientsService.UpdateAsync(Patient);
                await Navigation.PopAsync();
            });
        }

Artículo escrito por nuestros cracks del equipo movilidad.

Puedes encontrar todo el código en nuestro github.