Overview
La librería CodeDesignPlus.Net.EFCore
proporciona una serie de extensiones y configuraciones para trabajar con Entity Framework Core, facilitando la implementación de patrones de repositorio, paginación y manejo de excepciones entre otras funcionalidades.
Propósito y alcance
El objetivo de CodeDesignPlus.Net.EFCore es proporcionar una base sólida para interactuar con bases de datos utilizando Entity Framework Core, permitiendo a los desarrolladores implementar operaciones CRUD de manera eficiente y estandarizada. A través de sus extensiones y configuraciones, la librería simplifica la gestión de entidades, la paginación de resultados y el manejo de excepciones, mejorando la productividad y la calidad del código.
Principales características
- Configuración de Entidades: Extensiones para configurar propiedades base de las entidades y manejar la paginación de resultados de consultas.
- Excepciones Especializadas: Manejo de excepciones específicas para operaciones de EFCore.
- Registro de Configuraciones de Entidades: Métodos para registrar configuraciones de entidades de manera automática en el ModelBuilder.
- Operaciones de Repositorio: Implementaciones base para operaciones de creación, actualización, eliminación y transacciones dentro de un contexto de base de datos.
- Registro de Repositorios: Métodos para registrar repositorios de manera automática en el contenedor de dependencias.
Casos de uso típicos
- Implementación de operaciones CRUD en aplicaciones .NET Core.
- Configuración de propiedades base de entidades y manejo de paginación.
- Gestión de excepciones específicas para operaciones de EFCore.
- Registro automático de configuraciones de entidades y repositorios en el ModelBuilder y el contenedor de dependencias.
Componentes Principales
- Repositorio Base: Clase base para operaciones CRUD en un contexto de base de datos.
- Operación Base: Clase base para operaciones de creación, actualización y eliminación de entidades.
- Extensiones: Métodos de extensión para configurar entidades, manejar paginación y registrar configuraciones de entidades y repositorios.
- Excepciones: Clases especializadas para manejar excepciones específicas de EFCore.
Directorysrc
DirectoryCodeDesignPlus.Net.EFCore
- Usings.cs
DirectoryExceptions
- EFCoreException.cs
DirectoryExtensions
- EFCoreExtensions.cs
- ServiceCollectionExtensions.cs
DirectoryOperations
- OperationBase.cs
DirectoryRepository
- RepositoryBase.cs
DirectoryCodeDesignPlus.Net.EFCore.Abstractions
- IRepositoryBase.cs
- Usings.cs
DirectoryOperations
- ICreateOperation.cs
- IDeleteOperation.cs
- IOperationBase.cs
- IUpdateOperation.cs
DirectoryOptions
- ClaimsOption.cs
- EFCoreOptions.cs
Primeros Pasos
En esta sección, aprenderás a instalar y configurar la librería CodeDesignPlus.Net.EFCore
en tu proyecto de .NET. Además, explorarás los servicios, métodos de extensión y excepciones que proporciona la librería para interactuar con bases de datos utilizando Entity Framework Core.
Requisitos previos
- .NET 8 o superior.
- Conocimientos básicos de Entity Framework Core y operaciones CRUD.
Instalación
Para instalar la librería CodeDesignPlus.Net.EFCore
, puedes utilizar el administrador de paquetes NuGet o la CLI de .NET. A continución, se muestra un ejemplo de cómo instalar la librería utilizando la CLI de .NET:
dotnet add package CodeDesignPlus.Net.EFCore
Install-Package CodeDesignPlus.Net.EFCore
<PackageReference Include="CodeDesignPlus.Net.EFCore" Version="1.0.0" />
Configuración básica
-
Asignar las opciones de configuración en el
appsettings.json
:{"ConnectionStrings": {"DefaultConnection": "Server=localhost,1433;Database=db_test;User Id=sa;Password=Password123;Encrypt=false"},"Core": {"Business": "CodeDesignPlus","AppName": "sample-efcore-repositorybase","Version": "v1","Description": "Sample of CodeDesignPlus.Net.Core","Contact": {"Name": "CodeDesignPlus","Email": "custom@outlook.com"}},"EFCore": {"Enable": true,"RegisterRepositories": true}} -
Registrar los servicios en el contenedor de dependencias:
//...serviceCollection.AddEFCore<OrderContext>(configuration);serviceCollection.AddDbContext<OrderContext>(options =>{options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), x =>{x.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);});});
Ejemplo rápido
El proyecto de ejemplo CodeDesignPlus.Net.EFCore.Sample
contiene un par de ejemplos exponiendo el uso de IOperationBase
y RepositoryBase
.
using CodeDesignPlus.Net.EFCore.Extensions;using CodeDesignPlus.Net.EFCore.Sample.RepositoryBase;using CodeDesignPlus.Net.EFCore.Sample.RepositoryBase.Entities;using CodeDesignPlus.Net.EFCore.Sample.RepositoryBase.Repositories;using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;
var configurationBuilder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
var configuration = configurationBuilder.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(configuration);serviceCollection.AddEFCore<OrderContext>(configuration);
serviceCollection.AddDbContext<OrderContext>(options =>{ options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), x => { x.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null); });});
var serviceProvider = serviceCollection.BuildServiceProvider();
var context = serviceProvider.GetRequiredService<OrderContext>();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var orderRepository = serviceProvider.GetRequiredService<IOrderRepository>();
// Createvar order = OrderAggregate.Create(Guid.NewGuid(), "Order 1", "Description 1", 1000, Guid.NewGuid(), Guid.NewGuid());
await orderRepository.CreateAsync(order);
// Readvar orders = await orderRepository.GetEntity<OrderAggregate>().ToListAsync();
foreach (var item in orders){ Console.WriteLine($"Id: {item.Id}"); Console.WriteLine($"Name: {item.Name}"); Console.WriteLine($"Description: {item.Description}"); Console.WriteLine($"Price: {item.Price}"); Console.WriteLine($"Created At: {item.CreatedAt}"); Console.WriteLine($"Created By: {item.CreatedBy}"); Console.WriteLine($"Is Active: {item.IsActive}"); Console.WriteLine($"Tenant: {item.Tenant}"); Console.WriteLine();}
// Update
order = orderRepository.GetEntity<OrderAggregate>().FirstOrDefault(x => x.Id == order.Id);
if (order is not null){ order.Update("Order 1 Updated", "Description 1 Updated", 2000, Guid.NewGuid());
await orderRepository.UpdateAsync(order);}
// Deleteawait orderRepository.DeleteAsync<OrderAggregate>(x => x.Id == order.Id);
// CreateRangeAsyncvar ordersList = new List<OrderAggregate>{ OrderAggregate.Create(Guid.NewGuid(), "Order 2", "Description 2", 2000, Guid.NewGuid(), Guid.NewGuid()), OrderAggregate.Create(Guid.NewGuid(), "Order 3", "Description 3", 3000, Guid.NewGuid(), Guid.NewGuid()), OrderAggregate.Create(Guid.NewGuid(), "Order 4", "Description 4", 4000, Guid.NewGuid(), Guid.NewGuid()), OrderAggregate.Create(Guid.NewGuid(), "Order 5", "Description 5", 5000, Guid.NewGuid(), Guid.NewGuid()),};
await orderRepository.CreateRangeAsync(ordersList);
// UpdateRangeAsyncordersList = [.. orderRepository.GetEntity<OrderAggregate>().Where(x => x.Price > 3000)];
foreach (var item in ordersList){ item.Update(item.Name, item.Description, item.Price + 1000, Guid.NewGuid());}
await orderRepository.UpdateRangeAsync(ordersList);
// DeleteRangeAsyncordersList = [.. orderRepository.GetEntity<OrderAggregate>().Where(x => x.Price < 3000)];
await orderRepository.DeleteRangeAsync(ordersList);
// ChangeStateAsyncorder = orderRepository.GetEntity<OrderAggregate>().FirstOrDefault();
if (order is not null) await orderRepository.ChangeStateAsync<OrderAggregate>(order.Id, false, CancellationToken.None);
// TransactionAsyncawait orderRepository.TransactionAsync<bool>(async (context) =>{ var order = OrderAggregate.Create(Guid.NewGuid(), "Order 6", "Description 6", 6000, Guid.NewGuid(), Guid.NewGuid());
await orderRepository.CreateAsync(order);
order = orderRepository.GetEntity<OrderAggregate>().FirstOrDefault(x => x.Id == order.Id);
if (order is not null) { order.Update("Order 6 Updated", "Description 6 Updated", 7000, Guid.NewGuid());
await orderRepository.UpdateAsync(order); }
order = orderRepository.GetEntity<OrderAggregate>().FirstOrDefault(x => x.Id == order.Id);
if (order is not null) await orderRepository.DeleteAsync<OrderAggregate>(x => x.Id == order.Id);
});
// GetContext
var context2 = orderRepository.GetContext<OrderContext>();
Console.ReadLine();
using CodeDesignPlus.Net.EFCore.Extensions;using CodeDesignPlus.Net.EFCore.Sample.OperationBase;using CodeDesignPlus.Net.EFCore.Sample.OperationBase.Entities;using CodeDesignPlus.Net.EFCore.Sample.OperationBase.Repositories;using CodeDesignPlus.Net.EFCore.Sample.OperationBase.Services;using CodeDesignPlus.Net.Security.Abstractions;using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;
var configurationBuilder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
var configuration = configurationBuilder.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(configuration);serviceCollection.AddEFCore<OrderContext>(configuration);serviceCollection.AddSingleton<IUserContext, UserContext>();
serviceCollection.AddDbContext<OrderContext>(options =>{ options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), x => { x.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null); });});
var serviceProvider = serviceCollection.BuildServiceProvider();
var context = serviceProvider.GetRequiredService<OrderContext>();var user = serviceProvider.GetRequiredService<IUserContext>();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var orderRepository = serviceProvider.GetRequiredService<IOrderRepository>();
// Createvar order = OrderAggregate.Create(Guid.NewGuid(), "Order 1", "Description 1", 1000, user.IdUser, user.Tenant);
await orderRepository.CreateAsync(order);
// Updateorder = orderRepository.GetEntity<OrderAggregate>().FirstOrDefault(x => x.Id == order.Id);
if (order is not null){ order.Update("Order 1 Updated", "Description 1 Updated", 2000, user.IdUser);
await orderRepository.UpdateAsync(order.Id, order, CancellationToken.None);}
// Deleteawait orderRepository.DeleteAsync(order.Id);
Console.ReadLine();
Métodos de extensión
La librería CodeDesignPlus.Net.EFCore
proporciona una serie de métodos de extensión que facilitan la implementación de patrones de diseño comunes. A continuación, se presentan los métodos de extensión disponibles junto con una breve descripción de cada uno. Para obtener más detalles sobre cómo utilizar estos métodos, puedes hacer clic en los enlaces proporcionados.
ServiceCollection
ServiceCollectionExtensions
proporciona métodos de extensión para registrar servicios en el contenedor de dependencias, como configuraciones de Entity Framework Core y operaciones de repositorio.
EFCoreExtensions
Proporciona métodos de extensión para configurar entidades, manejar paginación y registrar configuraciones de entidades y repositorios.
Opciones de configuración
La librería CodeDesignPlus.Net.EFCore
ofrece una serie de opciones de configuración que permiten personalizar el comportamiento de la biblioteca. A continuación, se presentan las opciones de configuración disponibles junto con una breve descripción de cada una. Para obtener más detalles sobre cómo configurar estas opciones, puedes hacer clic en los enlaces proporcionados.
Servicios
La biblioteca CodeDesignPlus.Net.EFCore
ofrece una variedad de servicios esenciales para la gestión de operaciones en una base de datos utilizando Entity Framework Core. A continuación, se presenta una lista de estos servicios junto con una breve descripción de cada uno. Para obtener más detalles sobre cada servicio, puedes hacer clic en los enlaces proporcionados.
Create Operation
Proporciona una interfaz para crear un registro en el repositorio y asignar información a las propiedades transversales de la entidad. Este servicio se encuentra implementado en la clase OperationBase
.
Delete Operation
Proporciona una interfaz para eliminar un registro en el repositorio y asignar información a las propiedades transversales de la entidad. Este servicio se encuentra implementado en la clase OperationBase
.
Update Operation
Permite al repositorio actualizar un registro asignando la información a las propiedades transversales de la entidad. Este servicio se encuentra implementado en la clase OperationBase
.
RepositoryBase y OperationBase
La diferencia principal entre usar OperationBase y RepositoryBase para la creación, actualización y eliminación de entidades radica en las funcionalidades adicionales y el enfoque de cada clase:
-
RepositoryBase:
Proporciona métodos básicos y comunes para interactuar con la base de datos, como crear, actualizar, eliminar y consultar entidades.
Características Clave:
- Operaciones CRUD Básicas: Métodos para crear, actualizar, eliminar y consultar entidades.
- Contexto de Base de Datos: Utiliza el DbContext para realizar operaciones en la base de datos.
-
OperationBase:
Extiende las funcionalidades de
RepositoryBase
añadiendo gestión de propiedades transversales y auditoría, comoCreatedBy
,CreatedAt
,UpdatedBy
yUpdatedAt
.Características Clave:
- Propiedades Transversales: Asigna automáticamente información de auditoría a las entidades (
CreatedBy
,CreatedAt
,UpdatedBy
,UpdatedAt
). - Lista de Exclusión: Mantiene una lista de propiedades que no deben ser actualizadas durante las operaciones de actualización.
- Integración con Usuario Autenticado: Utiliza la información del usuario autenticado (
IUserContext
) para completar las propiedades de auditoría. - Operaciones CRUD: Hereda y extiende las operaciones CRUD de
RepositoryBase
.
- Propiedades Transversales: Asigna automáticamente información de auditoría a las entidades (
Diferencias Clave
- Auditoría y Propiedades Transversales:
OperationBase
asigna automáticamente información de auditoría a las entidades, mientras queRepositoryBase
no lo hace.
- Lista de Exclusión:
OperationBase
mantiene una lista de propiedades que no deben ser actualizadas, asegurando que ciertas propiedades (comoId
,CreatedBy
,CreatedAt
) no se modifiquen accidentalmente.
- Usuario Autenticado:
OperationBase
utiliza la información del usuario autenticado (IUserContext
) para completar las propiedades de auditoría, proporcionando un mayor nivel de trazabilidad.
- Uso Genérico vs. Específico:
RepositoryBase
es más genérico y puede ser utilizado para cualquier entidad sin necesidad de gestión de auditoría.OperationBase
es más específico y está diseñado para escenarios donde la auditoría y la gestión de propiedades transversales son necesarias.
Para obtener más información sobre cómo utilizar RepositoryBase
y OperationBase
, puedes hacer clic en los enlaces proporcionados.
Conclusiones
En esta guía, hemos explorado la librería CodeDesignPlus.Net.EFCore
y sus principales características, servicios y métodos de extensión. Hemos aprendido cómo instalar y configurar la librería en un proyecto de .NET, y hemos visto ejemplos de uso de RepositoryBase
y OperationBase
para interactuar con bases de datos utilizando Entity Framework Core.