15/11/2023 | Software Embebido,Tecnologías

PostgreSQL y Entity Framework en .NET

¿Os interesa conocer más sobre Entity Framework, saber cómo instalarlo y ver un ejemplo? En este post de nuestro compañero Manuel despejamos todas las dudas que puedas tener.

Comencemos por el principio, ¿qué es un ORM?

ORM (Object Relational Mapper)

Un ORM es un framework que asigna entidades de un objeto (como propiedades y clases) de una aplicación a entidades relacionales (como tablas y columnas) de una base de datos.

Entity Framework

Entity Framework Core es un ORM para .NET, admite consultas LINQ, seguimiento de cambios, actualizaciones y migraciones de esquemas de bases de datos. EF Core funciona con SQL Server, Azure SQL Database, SQLite, Azure Cosmos DB, MySQL, PostreSQL y otras bases de datos a través de una API.  En este caso conoceremos su uso básico con PosgreSQL.

Entity Framework (EF) permite a los desarrolladores trabajar con una base de datos utilizando los objetos de .NET. Nos permite evitar tener que escribir la mayoría del código necesario para acceder a los datos de una base de datos.

La API que EF proporciona nos permite un acceso a los datos de manera rápida y fácil de usar. Podemos usar EF Core en una aplicación de dos maneras diferentes, Code-First y Database-First. 

El enfoque Code-First se utiliza si se desea crear y administrar la base de datos desde el código de la aplicación. Podemos crear la base de datos si aún no existe, en tiempo de ejecución o mediante migraciones. 

El enfoque Database-First, se utiliza si queremos crear nuestra base de datos primero y luego podemos generar las clases de nuestros modelos para el código de nuestra aplicación.

Para este caso vamos utilizar el enfoque Code-First.

Instalación

Para instalar Entity Framework en nuestro proyecto de C#, ejecutamos el siguiente comando:

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 7.0.11

Con inyección de dependencias podemos crear una clase que será nuestro servicio de base de datos, la cuál será nuestro contexto para hacer las conexiones con la base de datos.

Creamos una interfaz en un nuevo archivo IDatabaseService.cs con:

public interface IDatabaseService
{
public bool CanConnect();
}

Después creamos una nueva clase dónde vamos a implementar esta interface, DatabaseService.cs :

public class DatabaseService : DbContext, IDatabaseService
{
public DatabaseService()
: base()
{
Console.WriteLine("DatabaseService started");
}
public bool CanConnect()
{
bool canConnect = this.Database.CanConnect();
if (!canConnect)
{
Console.WriteLine("Couldn't connect to DB... is the DB running? Provider is " + this.Database.ProviderName);
}
return canConnect;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("Host=127.0.0.1;Database=workstationdb;Username=user1;Password=pass");
optionsBuilder.UseExceptionProcessor();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}

En la función OnConfiguring indicamos nuestro string de conexión a la base de datos que tenemos con PostreSQL. 

Ejemplo

Creamos una clase que representa una tabla en nuestra base de datos, donde indicaremos las columnas con su tipo de datos, así como las anotaciones correspondientes para casos cómo límite de caracteres, llaves primarias o foráneas, etc.

public partial class Person
{
[Key]
public uint Id { get; set; }
[StringLength(50)]
public string Name { get; set; } = null!;
public long Age { get; set; }
}

Como podemos ver, estamos indicando que la propiedad Id será la llave primaria de nuestra tabla y que la propiedad Name tendrá un límite de 50 caracteres.

Ahora necesitamos crear un DbSet que haga referencia a nuestra clase dentro de nuestro DbContext.

protected virtual DbSet<Person> People { get; set; } = null!;

Para generar esta tabla en PostgreSQL, vamos a ejecutar:

dotnet ef migrations add InitialMigration

Donde InitialMigration es el nombre de nuestra migración, la cual generará los archivos necesarios para crear nuestra tabla en tiempo ejecución, en caso de que ésta no exista.

Dentro de InitialMigration.cs vemos que en la función Up, se crea la tabla utilizando MigrationBuilder.

Cuando ejecutemos nuestra aplicación la próxima vez, la nueva migración se ejecutará y creará la tabla en la base de datos. Con esto ya podemos crear funciones para insertar, borrar, consultar o modificar datos de nuestra tabla. 

Dentro de nuestra clase DbContext podemos agregar una función para consultar la tabla:

Como podemos ver la función nos devuelve una List<Person> del contenido de DbSet<Person>. 

Para agregar un nuevo elemento a la tabla, podemos crear la siguiente función dentro de nuestro dbContext: 

public async Task<string> AddPerson(Person person)
{
var result = string.Empty;


try
{
this.People.Add(person);
await this.SaveChangesAsync();
}
catch (Exception e) when (e is UniqueConstraintException || e is CannotInsertNullException ||
e is MaxLengthExceededException || e is Exception)
{
Log.Error("AddPerson Exception: " + e.Message);
result = e.Message;
}


return result;
}

Si el objeto person cumple con las condiciones de la tabla se agrega a la lista del DbSet de lo contrario lanzará alguna de las excepciones.

Para eliminar un elemento, podemos hacer referencia al objeto que queremos eliminar, o bien hacer una búsqueda por alguna de sus propiedades. En el siguiente ejemplo buscamos al elemento por su Id y lo eliminamos. Toma en cuenta que de esta manera también podemos eliminar un rango de elementos con un parámetro especificado, cómo eliminar todos los elementos con el mismo nombre.

public async Task<string> RemovePersonById(uint id)
{
var itemsToDelete = this.People.Where(x => x.Id == id);
var result = string.Empty;


if (itemsToDelete.Count() > 0)
{
try
{
this.People.RemoveRange(itemsToDelete);
await this.SaveChangesAsync();
}
catch (Exception e)
{
Log.Error("RemovePersonById RemoveRange error: " + e.GetType());
result = e.Message;
}
}
else
{
result = Localization.Resources.NotExists;
}


return result;
}

Conclusión

Como hemos visto, con Entity Framework podemos realizar consultas y operaciones con nuestra base de datos y desglosar la información de nuestras tablas de una forma clara y simple de leer. Al tener nuestros elementos de la base de datos contenidos en objetos relacionados, podemos utilizarlos a lo largo de toda nuestra aplicación.

Compartir en:

Relacionados