Saltar a contenido

Andreani.ARQ.Mongo

Overview

Se desarrolló la librería Andreani.ARQ.Mongo para realizar la implementación de MongoDB.Driver .El objetivo es abstraer de las configuraciones a lxs desarrolladorxs y disponibilizar de interfaces comunes para una rápida adopción y uso de las tecnologías.

Info

Andreani.ARQ.Mongo utiliza la librería de MongoDB.Driver como base para las interacciones con la base de datos. ver MongoDB.Driver

Instalación

  1. Instalar en el proyecto Application la dependencia con Core.MongoDb
    dotnet add package Andreani.Arq.Core.MongoDb
    
  2. Instalar en el proyecto Infreastructure la dependencia con Mongo
    dotnet add package Andreani.Arq.Mongo
    
  3. Instalar en el proyecto Infreastructure la dependencia con Observability.ElasticApm.Mongo o Observability.OpenTelemetry.Mongo
    dotnet add package Andreani.Arq.Observability.ElasticApm.Mongo
    dotnet add package Andreani.Arq.Observability.OpenTelemetry.Mongo
    

Configuración

Para realizar la configuración debemos, en principio instalar como paquete nuget la librería Andreani.ARQ.Mongo.

En los archivos de configuración appsettings debemos disponer de una sección con la configuración de Mongo

  {
    "MongoRegistry":{
        "ConnectionString": "mongodb://localhost:27017",
        "DataBase": "NameDb"
    }
  }
    MongoRegistry:
        ConnectionString: "mongodb://localhost:27017"
        DataBase: "NameDb"

El parámetro ConnectionString será la connection que tome la libreria.

Para incluir la configuración a nuestro proyecto la siguiente línea al bootstrap de la capa de Infrastructure

public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddMongo(configuration);

            return services;
        }

El método AddMongo realiza la configuración y la inyección de dependencias.

Al método AddMongo se puede configurar con:

public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddMongo(configuration, configSectionName: "MongoRegistry");

            return services;
        }

  1. configSectionName: es el nombre de la sección de configuración. Por defecto: MongoRegistry

Healthcheck

La librería ya tiene la configuración de healthcheck, se complementa con la configuración de Andreani.ARQ.WebHost, para acceder a los healthcheck debe ivocar la ruta: http://*:*/health o http://*:*/healthcheck para obtener más info.

Interfaces Disponibles

En la nueva versión de la librería Mongo implementa 2 interfaces, una Generica IMongoRepository<Entity>, y otra común IMongoRepository, la gran diferencia es que la Interface Generica se va utilizar para el manejo de una entidad especifica ( la misma cuenta con las operaciones básicas de lectura y escritura)

IMongoRepository Generic

    public interface IMongoRepository<Entity>
    {
        List<Entity> GetAll();

        Task<List<Entity>> GetAllAsync();

        Entity GetOne(FilterDefinition<Entity> expression);

        Task<Entity> GetOneAsync(FilterDefinition<Entity> expression);

        List<Entity> Where(Expression<Func<Entity, bool>> expression = null, int skip = 0, int take = 0);

        List<Entity> Where(FilterDefinition<Entity> filter, int skip = 0, int take = 0);

        Task<List<Entity>> WhereAsync(Expression<Func<Entity, bool>> expression = null, int skip = 0, int take = 0);

        Task<List<Entity>> WhereAsync(FilterDefinition<Entity> filter, int skip = 0, int take = 0);

        void Insert(Entity entity);

        Task InsertAsync(Entity entity);

        void InsertRange(List<Entity> entities);

        Task InsertRangeAsync(List<Entity> entities);

        void Update(FilterDefinition<Entity> filter, UpdateDefinition<Entity> expression);

        void Update(Entity entity, FilterDefinition<Entity> expression);

        Task UpdateAsync(Entity entity, FilterDefinition<Entity> expression);

        Task UpdateAsync(FilterDefinition<Entity> filter, UpdateDefinition<Entity> expression);

        void UpdateRange(List<Entity> entities, FilterDefinition<Entity> expression);

        Task UpdateRangeAsync(List<Entity> entities, FilterDefinition<Entity> expression);

        void UpdateMany(FilterDefinition<Entity> filter, UpdateDefinition<Entity> expression);

        Task UpdateManyAsync(FilterDefinition<Entity> filter, UpdateDefinition<Entity> expression);

        void Delete(FilterDefinition<Entity> expression);

        Task DeleteAsync(FilterDefinition<Entity> expression);

        void DeleteRange(FilterDefinition<Entity> expression);

        Task DeleteRangeAsync(FilterDefinition<Entity> expression);
    }

, mientras que la Interface común se va a utilizar para manejo avanzado de la base y va a contar con los siguientes métodos:

IMongoRepository Común

    public interface IMongoRepository
    {
        void UseDatabase(Action<IMongoDatabase> action);

        TResponse UseDatabase<TResponse>(Func<IMongoDatabase, TResponse> action);

        Task UseDatabaseAsync(Func<IMongoDatabase, Task> action);

        Task<TResponse> UseDatabaseAsync<TResponse>(Func<IMongoDatabase, Task<TResponse>> action);

        TResponse UseCollection<TDocument, TResponse>(string name, Func<IMongoCollection<TDocument>, TResponse> action);

        TDocument UseCollection<TDocument>(string name, Func<IMongoCollection<TDocument>, TDocument> action);

        void UseCollection<TDocument>(string name, Action<IMongoCollection<TDocument>> action);

        Task<TDocument> UseCollectionAsync<TDocument>(string name, Func<IMongoCollection<TDocument>, Task<TDocument>> action);

        Task<TResponse> UseCollectionAsync<TDocument, TResponse>(string name, Func<IMongoCollection<TDocument>, Task<TResponse>> action);

        Task UseCollectionAsync<TDocument>(string name, Func<IMongoCollection<TDocument>, Task> action);

        void CreateCollection(string id);
    }

Tip

Ya no es obligatorio heredar de `MongoEntity` para poder usar la librería, y ahora recibe el tipo de dato que deseamos que sea muestro Id (`MongoEntity<PK>`).
Ya no existe el metodo `SetDocumentName` y por eso se creó el Attribute `CollectionName` en caso de que la collection tenga un nombre diferente al de la clase y se utiliza así:
            [CollectionName("Person")]
            public class Person : MongoEntity<string>
            {
                public string Nombre { get; set; }
                public string Apellido { get; set; }
            }

IMongoRepository Generic

GetOne

GetOneAsync(FilterDefinition expression) agrega un filtro de MongoDB.Driver a la consulta.

        var filter = Builders<Person>.Filter.Eq(x => x.Id, request.Id);

        var person = await _repository.GetOneAsync(filter);

Update

UpdateAsync(Entity entity, FilterDefinition expression)

    public async Task<Response<string>> Handle(UpdatePersonCommand request, CancellationToken cancellationToken)
    {
        var filter = Builders<Person>.Filter.Eq(x => x.Id, request.Id);
        var person = await _repository.GetOneAsync(filter);
        var response = new Response<string>();
        if (person is null)
        {
            response.AddNotification("#3123", nameof(request.Id), string.Format(ErrorMessage.NOT_FOUND_RECORD, "Person", request.Id));
            response.StatusCode = System.Net.HttpStatusCode.NotFound;
            return response;
        }
        person.Nombre = request.Nombre;
        person.Apellido = request.Apellido;

        await _repository.UpdateAsync(person, filter);

        return response;
    }

UpdateAsync(FilterDefinition filter, UpdateDefinition expression)

    public async Task<Response<string>> Handle(UpdatePersonCommand request, CancellationToken cancellationToken)
    {
        var filter = Builders<Person>.Filter.Eq(x => x.Id, request.Id);
        var person = await _repository.GetOneAsync(filter);
        var response = new Response<string>();
        if (person is null)
        {
            response.AddNotification("#3123", nameof(request.Id), string.Format(ErrorMessage.NOT_FOUND_RECORD, "Person", request.Id));
            response.StatusCode = System.Net.HttpStatusCode.NotFound;
            return response;
        }

        var update= Builders < Person >.Update
            .Set(x => x.Nombre, request.Nombre)
            .Set(x=> x.Apellido,request.Apellido);

        await _repository.UpdateAsync(filter, update);

        return response;
    }

Tip

El `UpdateMany` es parecido al `UpdateAsync(FilterDefinition<Entity> filter, UpdateDefinition<Entity> expression)` pero este actualiza a todas las entidades que encuentre con el filtro y le setea los datos que definimos en el `UpdateDefinition`.

Where

Where(FilterDefinition filter, int skip = 0, int take = 0); agrega un filtro de MongoDB.Driver a la consulta.

        var filter = Builders<MyEntity>.Filter.Eq("name", "architecture-it");

        var listArchitecture = _repository.Where(filter);

Where(Expression> expression = null, int skip = 0, int take = 0); agrega una expresion lambda a la consulta.

        var documentMailArchitecture = _repository.Where(p => p.User.Mail.Equals("architecture-it@andreani.com"));

IMongoRepository Común

UseCollection

UseCollection es una función que inyecta la Collection, esta pensado para utilizarse en caso de necesitar actualizar un modelo complejo o utilizar las funciones del MongoDb.Driver que no estan disponibles desde la librería.

        var filter = Builders<MyEntity>.Filter.Eq("name", "architecture-it")

        var documentArchitecture = await _repository.UseCollectionAsync<MyEntity>("nameCollection",async con => {
                return await con.Find(filter).FirstOrDefaultAsync();
            });
        var filter = Builders<long>.Filter.Eq("name", "architecture-it");

        var totalDocumentNameArchitecture = _repository.UseCollection<long>("nameCollection", con => {
            return con.CountDocuments(filter);
        });