Giter Site home page Giter Site logo

anton-martyniuk / modern Goto Github PK

View Code? Open in Web Editor NEW
17.0 3.0 2.0 598 KB

.NET modern tools for fast and efficient development

License: Apache License 2.0

C# 100.00%
aspnetcore controllers cqrs cshap dapper dotnet efcore genericrepository litedb mongodb

modern's Introduction

Modern

What is Modern?

Modern is a set of modern .NET tools ๐Ÿ”จ ๐Ÿ”ง for fast and efficient development of common backend tasks. It allows to create a production ready applications with just set of models and configuration which can be further extended. Modern tool are flexible, easily changeable and extendable.
It includes the following components:

  • generic repositories for SQL and NoSQL databases
  • generic services with and without caching support
  • generic in memory services with in-memory filtering capabilities
  • in-memory and redis generic caches
  • generic set of CQRS queries and commands over repository (if you prefer CQRS over services)
  • generic controllers for all types of services
  • OData controllers for all types of services

For more information - see full documentation here.

Examples for all types of components - see here.


Table of contents ๐Ÿ“‘

How to get started?

Lets create a Web Api with CRUD operations over Airplane entities. We need a repository, service and controller.

  1. Install the following Nuget packages:
  1. Create classes for the following models: AirplaneDto and AirplaneDbo.

  2. Create an EF Core DbContext for accessing the AirplaneDbo.

  3. Register the Modern builder in DI and add the following components:

builder.Services
    .AddModern()
    .AddRepositoriesEfCore(options =>
    {
        options.AddRepository<FlyingDbContext, AirplaneDbo, long>();
    })
    .AddServices(options =>
    {
        options.AddService<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    })
    .AddControllers(options =>
    {
        options.AddController<CreateRequest, UpdateRequest, AirplaneDto, AirplaneDbo, long>();
    });

As a result a production ready API will be created:

GET ๐Ÿ”ต
/Airplanes/get/{id}

GET ๐Ÿ”ต ๐Ÿ”ต
/Airplanes/get

POST โœ…
/Airplanes/create

POST โœ… โœ…
/Airplanes/create-many

PUT ใ€ฝ๏ธ
/Airplanes/update/{id}

PUT ใ€ฝ๏ธ ใ€ฝ๏ธ
/Airplanes/update-many

PATCH ๐Ÿ’ฒ
/Airplanes/patch/{id}

DELETE โŒ
/Airplanes/delete/{id}

DELETE โŒ โŒ
/Airplanes/delete-many

Roadmap โžก๏ธ ๐Ÿ“…

The following features will be implemented in the next releases:

  • Assembly scan in DI packages
  • Unit and integration tests
  • MinimalsApis
  • Reflection improvements

Repositories

Modern generic repository is divided into 2 interfaces: IModernQueryRepository<TEntity, TId> and IModernCrudRepository<TEntity, TId>. IModernQueryRepository has the following methods:

Task<TEntity> GetByIdAsync(TId id, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<TEntity?> TryGetByIdAsync(TId id, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<IEnumerable<TEntity>> GetAllAsync(EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<long> CountAsync(CancellationToken cancellationToken = default);

Task<long> CountAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null,
    CancellationToken cancellationToken = default);

Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<TEntity?> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<TEntity?> SingleOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<PagedResult<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> predicate, int pageNumber, int pageSize, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

IQueryable<TEntity> AsQueryable();

IModernCrudRepository has the following methods:

Task<TEntity> CreateAsync(TEntity entity, CancellationToken cancellationToken = default);

Task<List<TEntity>> CreateAsync(List<TEntity> entities, CancellationToken cancellationToken = default);

Task<TEntity> UpdateAsync(TId id, TEntity entity, CancellationToken cancellationToken = default);

Task<List<TEntity>> UpdateAsync(List<TEntity> entities, CancellationToken cancellationToken = default);

Task<TEntity> UpdateAsync(TId id, Action<TEntity> update, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(TId id, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(List<TId> ids, CancellationToken cancellationToken = default);

Task<TEntity> DeleteAndReturnAsync(TId id, CancellationToken cancellationToken = default);

Repositories for SQL databases ๐Ÿ“

Modern generic repositories for SQL databases are built on top of 2 the following ORM frameworks:

  • EF Core
  • Dapper

To use EF Core repository install the Modern.Repositories.EFCore.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesEfCore(options =>
    {
        options.AddRepository<FlyingDbContext, AirplaneDbo, long>(useDbFactory: false);
    });

Specify the type of EF Core DbContext, Dbo entity model and primary key. useDbFactory parameter indicates whether repository with DbContextFactory should be used. The default value is false.

โ„น๏ธ Use this parameter if you plan to inherit from this generic repository and extend or change its functionality.
When using DbContextFactory every repository creates and closes a database connection in each method.
When NOT using DbContextFactory repository shares the same database connection during its lifetime.

โš ๏ธ It is not recommended to use useDbFactory = false when repository is registered as SingleInstance, otherwise a single database connection will persist during the whole application lifetime

To use Dapper repository install the Modern.Repositories.Dapper.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesDapper(options =>
    {
        options.ProvideDatabaseConnection(() => new NpgsqlConnection(connectionString));
        options.AddRepository<AirplaneDapperMapping, AirplaneDbo, long>();
    });

Specify the type of Dapper mapping class, Dbo entity model and primary key.
A dapper needs to know how to create a database connection. Since there are multiple database connection classes - provide the needed one using ProvideDatabaseConnection method. Dapper repository requires to have a small mapping class that way generic repository can match the entity property name with database table column.

โ„น๏ธ Mapping class for Dapper is a part of Modern tools and not a part of Dapper library

For example consider the following mapping class:

public class AirplaneDapperMapping : DapperEntityMapping<AirplaneDbo>
{
    protected override void CreateMapping()
    {
        Table("db_schema_name.airplanes")
            .Id(nameof(AirplaneDbo.Id), "id")
            .Column(nameof(AirplaneDbo.YearOfManufacture), "year_of_manufacture")
            .Column(nameof(AirplaneDbo.ModelId), "model_id")
            //...
            ;
    }
}

Repositories for No SQL databases ๐Ÿ“

Modern generic repositories for No SQL databases are built on of the following NoSQL databases:

  • MongoDB
  • LiteDb (embedded single-file NoSQL database)

To use MongoDB repository install the Modern.Repositories.MongoDB.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesMongoDb(options =>
    {
        options.ConfigureMongoDbClient(mongoDbConnectionString);
        options.AddRepository<AirplaneDbo, string>("database_name", "collection_name");
    });

Specify the type of Dbo entity model and "_id" key.
Provide the connection string in ConfigureMongoDbClient method. You can also use the second parameter updateSettings and configure the custom parameters in a MongoClientSettings class of MongoDB Driver.

To use LiteDB repository install the Modern.Repositories.LiteDB.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesLiteDb(options =>
    {
        options.AddRepository<AirplaneDbo, string>("connection_string", "collection_name");
    });

Specify the type of Dbo entity model and "_id" key.

โ„น๏ธ Right out of the box LiteDB official library supports only synchronous methods. To use asynchronous methods a third party library can be used. Modern libraries support asynchronous methods in LiteDB using litedb-async library

โš ๏ธ DISCLAIMER: LiteDb async repository uses litedb-async library which is not an official LiteDb project. Modern libraries are NOT responsible for any problems with litedb-async library, so use this package at your own risk.

To use LiteDB Async repository install the Modern.Repositories.LiteDB.Async.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesLiteDbAsync(options =>
    {
        options.AddRepository<AirplaneDbo, long>("connection_string", "collection_name");
    });

Specify the type of Dbo entity model and "_id" key.

Services ๐Ÿ“

Modern generic service is divided into 2 interfaces: IModernQueryService<TEntityDto, TEntityDbo, TId> and IModernCrudService<TEntityDto, TEntityDbo, TId>. IModernQueryService has the following methods:

Task<TEntityDto> GetByIdAsync(TId id, CancellationToken cancellationToken = default);

Task<TEntityDto?> TryGetByIdAsync(TId id, CancellationToken cancellationToken = default);

Task<List<TEntityDto>> GetAllAsync(CancellationToken cancellationToken = default);

Task<long> CountAsync(CancellationToken cancellationToken = default);

Task<long> CountAsync(Expression<Func<TEntityDbo, bool>> predicate, CancellationToken cancellationToken = default);

Task<bool> ExistsAsync(Expression<Func<TEntityDbo, bool>> predicate, CancellationToken cancellationToken = default);

Task<TEntityDto?> FirstOrDefaultAsync(Expression<Func<TEntityDbo, bool>> predicate, CancellationToken cancellationToken = default);

Task<TEntityDto?> SingleOrDefaultAsync(Expression<Func<TEntityDbo, bool>> predicate, CancellationToken cancellationToken = default);

Task<List<TEntityDto>> WhereAsync(Expression<Func<TEntityDbo, bool>> predicate, CancellationToken cancellationToken = default);

Task<PagedResult<TEntityDto>> WhereAsync(Expression<Func<TEntityDbo, bool>> predicate, int pageNumber, int pageSize, CancellationToken cancellationToken = default);

IQueryable<TEntityDbo> AsQueryable();

IModernCrudService has the following methods:

Task<TEntityDto> CreateAsync(TEntityDto entity, CancellationToken cancellationToken = default);

Task<List<TEntityDto>> CreateAsync(List<TEntityDto> entities, CancellationToken cancellationToken = default);

Task<TEntityDto> UpdateAsync(TId id, TEntityDto entity, CancellationToken cancellationToken = default);

Task<List<TEntityDto>> UpdateAsync(List<TEntityDto> entities, CancellationToken cancellationToken = default);

Task<TEntityDto> UpdateAsync(TId id, Action<TEntityDto> update, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(TId id, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(List<TId> ids, CancellationToken cancellationToken = default);

Task<TEntityDto> DeleteAndReturnAsync(TId id, CancellationToken cancellationToken = default);

Modern generic services use Modern generic repositories to perform CRUD operations. To use Service install the Modern.Services.DataStore.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddServices(options =>
    {
        options.AddService<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

Specify the type of Dto and dbo entity models, primary key and modern repository.
Service requires one of modern repositories to be registered.

Services with caching ๐Ÿ“

Modern generic services with caching support use Modern generic repositories and cache to perform CRUD operations. To use Service with caching install the Modern.Services.DataStore.Cached.DependencyInjection and Modern.Cache.InMemory.DependencyInjection Nuget packages and register them within Modern builder in DI:

builder.Services
    .AddModern()
    .AddInMemoryCache(options =>
    {
        options.AddCache<AirplaneDto, long>();
        
        options.CacheSettings.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
        options.CacheSettings.SlidingExpiration = TimeSpan.FromMinutes(10);
    })
    .AddCachedServices(options =>
    {
        options.AddService<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

Or install the Modern.Services.DataStore.Cached.DependencyInjection and Modern.Cache.Redis.DependencyInjection Nuget packages and register them within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRedisCache(options =>
    {
        options.AddCache<AirplaneDto, long>();

        options.RedisConfiguration.ConnectionString = redisConnectionString;
        options.RedisConfiguration.AbortOnConnectFail = false;
        options.RedisCacheSettings.ExpiresIn = TimeSpan.FromMinutes(30);
    })
    .AddCachedServices(options =>
    {
        options.AddService<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

When registering service specify the type of Dto and dbo entity models, primary key and modern repository.
Service requires one of modern repositories to be registered.
When using InMemoryCache modify the CacheSettings of type MemoryCacheEntryOptions to specify the cache expiration time.
When using RedisCache modify the RedisConfiguration of StackExchange.Redis package and expiration time in RedisCacheSettings.

Services In Memory ๐Ÿ“

Modern generic in memory services use Modern generic repositories and in memory cache to perform CRUD operations. In Memory Services holds all the data in cache and performs filtering in the memory. While CachedService only use cache for the items it retrieves frequently. To use In Memory Service install the Modern.Services.DataStore.InMemory.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddInMemoryServices(options =>
    {
        options.AddService<AirplaneDbo, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

Specify the type of Dto and dbo entity models, primary key and modern repository.
Service requires one of modern repositories to be registered.
The cache is registered under the hood and there is no Redis support as Redis doesn't support LINQ expressions on its items. The cache can be changed to the custom one if needed.

CQRS ๐Ÿ“

Modern generic CQRS consist of Commands and Queries. CQRS has the following Queries:

GetAllQuery<TEntityDto, TId>() : IRequest<List<TEntityDto>>

GetByIdQuery<TEntityDto, TId>(TId Id) : IRequest<TEntityDto>

TryGetByIdQuery<TEntityDto, TId>(TId Id) : IRequest<TEntityDto?>

GetCountAllQuery<TEntityDto, TId> : IRequest<long>

GetCountQuery<TEntityDbo, TId>(Expression<Func<TEntityDbo, bool>> Predicate) : IRequest<long>

GetExistsQuery<TEntityDbo, TId>(Expression<Func<TEntityDbo, bool>> Predicate) : IRequest<bool>

GetFirstOrDefaultQuery<TEntityDto, TEntityDbo, TId>(Expression<Func<TEntityDbo, bool>> Predicate) : IRequest<TEntityDto?>

GetSingleOrDefaultQuery<TEntityDto, TEntityDbo, TId>(Expression<Func<TEntityDbo, bool>> Predicate) : IRequest<TEntityDto?>

GetWhereQuery<TEntityDto, TEntityDbo, TId>(Expression<Func<TEntityDbo, bool>> Predicate) : IRequest<List<TEntityDto>>

GetWherePagedQuery<TEntityDto, TEntityDbo, TId> : IRequest<PagedResult<TEntityDto>>

CQRS has the following Commands:

CreateEntityCommand<TEntityDto>(TEntityDto Entity) : IRequest<TEntityDto>

CreateEntitiesCommand<TEntityDto>(List<TEntityDto> Entities) : IRequest<List<TEntityDto>>

UpdateEntityCommand<TEntityDto, TId>(TId Id, TEntityDto Entity) : IRequest<TEntityDto>

UpdateEntityByActionCommand<TEntityDto, TId>(TId Id, Action<TEntityDto> UpdateAction) : IRequest<TEntityDto>

UpdateEntitiesCommand<TEntityDto>(List<TEntityDto> Entities) : IRequest<List<TEntityDto>>

DeleteEntityCommand<TId>(TId Id) : IRequest<bool>

DeleteEntitiesCommand<TId>(List<TId> Ids) : IRequest<bool>

DeleteAndReturnEntityCommand<TEntityDto, TId>(TId Id) : IRequest<TEntityDto>

Modern generic CQRS consist of Commands and Queries which use Modern generic repositories to perform CRUD operations. To use CQRS install the Modern.CQRS.DataStore.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddCqrs(options =>
    {
        options.AddQueriesCommandsAndHandlersFor<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

Specify the type of Dto and dbo entity models, primary key and modern repository.
CQRS requires one of modern repositories to be registered.

CQRS with caching ๐Ÿ“

Modern generic CQRS Commands and Queries with caching support use Modern generic repositories and cache to perform CRUD operations. To use Service with caching install the Modern.Services.DataStore.Cached.DependencyInjection and Modern.Cache.InMemory.DependencyInjection Nuget packages and register them within Modern builder in DI:

builder.Services
    .AddModern()
    .AddInMemoryCache(options =>
    {
        options.AddCache<AirplaneDto, long>();
        
        options.CacheSettings.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30);
        options.CacheSettings.SlidingExpiration = TimeSpan.FromMinutes(10);
    })
    .AddCachedCqrs(options =>
    {
        options.AddQueriesCommandsAndHandlersFor<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

Or install the Modern.Services.DataStore.Cached.DependencyInjection and Modern.Cache.Redis.DependencyInjection Nuget packages and register them within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRedisCache(options =>
    {
        options.AddCache<AirplaneDto, long>();

        options.RedisConfiguration.ConnectionString = redisConnectionString;
        options.RedisConfiguration.AbortOnConnectFail = false;
        options.RedisCacheSettings.ExpiresIn = TimeSpan.FromMinutes(30);
    })
    .AddCachedCqrs(options =>
    {
        options.AddQueriesCommandsAndHandlersFor<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    });

Specify the type of Dto and dbo entity models, primary key and modern repository.
CQRS requires one of modern repositories to be registered.
When using InMemoryCache modify the CacheSettings of type MemoryCacheEntryOptions to specify the cache expiration time.
When using RedisCache modify the RedisConfiguration of StackExchange.Redis package and RedisCacheSettings expiration time.

Controllers ๐Ÿ“

Modern generic controller has the following HTTP endpoints:

[Route("api/[controller]")]
public class ModernController<TCreateRequest, TUpdateRequest, TEntityDto, TEntityDbo, TId> : ControllerBase
{
    [HttpGet("get/{id}")]
    Task<IActionResult> GetById([Required] TId id)
    
    [HttpGet("get")]
    Task<IActionResult> GetAll(CancellationToken cancellationToken)
    
    [HttpPost("create")]
    Task<IActionResult> Create([FromBody, Required] TCreateRequest request)
    
    [HttpPost("create-many")]
    Task<IActionResult> CreateMany([FromBody, Required] List<TCreateRequest> requests)
    
    [HttpPut("update/{id}")]
    Task<IActionResult> Update([Required] TId id, [FromBody, Required] TUpdateRequest request)
    
    [HttpPut("update-many")]
    Task<IActionResult> UpdateMany([FromBody, Required] List<TUpdateRequest> requests)
    
    [HttpPatch("patch/{id}")]
    Task<IActionResult> Patch([Required] TId id, [FromBody] JsonPatchDocument<TEntityDto> patch)
    
    [HttpDelete("delete/{id}")]
    Task<IActionResult> Delete([Required] TId id)
    
    [HttpDelete("delete-many")]
    Task<IActionResult> DeleteMany([Required] List<TId> ids)
}

Modern generic controllers use Modern generic services to perform CRUD operations. To use Controller install the Modern.Controllers.DataStore.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddControllers(options =>
    {
        options.AddController<CreateRequest, UpdateRequest, AirplaneDto, AirplaneDbo, long>();
    });

Specify the type of create and update requests, dto entity model and primary key.
Controller requires one of modern services to be registered: regular one or with caching.

Controllers CQRS ๐Ÿ“

Modern generic CQRS controllers use Modern CQRS Commands and Queries to perform CRUD operations. To use CQRS Controller install the Modern.Controllers.CQRS.DataStore.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddCqrsControllers(options =>
    {
        options.AddController<CreateRequest, UpdateRequest, AirplaneDto, AirplaneDbo, long>();
    });

Specify the type of create and update requests, dto entity model and primary key.
Controller requires CQRS Commands and Queries to be registered: regular one or with caching.

Controllers In Memory ๐Ÿ“

Modern generic controllers use Modern generic services to perform CRUD operations. To use In Memory Controller install the Modern.Controllers.DataStore.InMemory.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddInMemoryControllers(options =>
    {
        options.AddController<CreateRequest, UpdateRequest, AirplaneDto, AirplaneDbo, long>();
    });

Specify the type of create and update requests, dto entity model and primary key.
Controller requires a modern in memory service to be registered.

OData Controllers ๐Ÿ“

Modern generic OData controllers use Modern generic repositories to perform OData queries. To use OData Controller install the Modern.Controllers.DataStore.OData.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddODataControllers(options =>
    {
        options.AddController<AirplaneDbo, long>();
    });

Specify the type of dto entity model and primary key.
OData Controller requires one of modern repositories to be registered.

Also register OData in the DI:

builder.Services.AddControllers(options =>
{
})
//..
.AddOData(opt =>
{
    // Adjust settings as appropriate
    opt.AddRouteComponents("api/odata", GetEdmModel());
    opt.Select().Filter().Count().SkipToken().OrderBy().Expand().SetMaxTop(1000);
    opt.TimeZone = TimeZoneInfo.Utc;
});

IEdmModel GetEdmModel()
{
    // Adjust settings as appropriate
    var builder = new ODataConventionModelBuilder();
    builder.EnableLowerCamelCase();

    // Register your OData models here. Name of the EntitySet should correspond to the name of OData controller
    builder.EntitySet<AirplaneDbo>("airplanes");
    builder.EntityType<AirplaneDbo>();

    return builder.GetEdmModel();
}

OData Controllers In Memory ๐Ÿ“

Modern generic OData controllers use Modern generic repositories to perform OData queries. To use In Memory OData Controller install the Modern.Controllers.DataStore.InMemory.OData.DependencyInjection Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddInMemoryODataControllers(options =>
    {
        options.AddController<AirplaneDbo, long>();
    });

Specify the type of dto entity model and primary key.
OData Controller requires one of modern repositories to be registered.
Remember to configure OData in DI as mentioned in see OData Controllers

Support My Work ๐ŸŒŸ

If you find this package helpful, consider supporting my work by buying me a coffee โ˜•!
Your support is greatly appreciated and helps me continue developing and maintaining this project.
You can also give me a โญ on github to make my package more relevant to others.

Buy me a coffee

Thank you for your support!

modern's People

Contributors

anton-martyniuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

modern's Issues

Cache mismatch

Hi

When option AddOrUpdateInCacheWhenEntityIsUpdated is enabled, Update method stores dto to cache without includes. When option is disabled we can take only outdated dto from cache with Get methods
So we in trap)

I think it is necessary to delete from the cache when updating and the option AddOrUpdateInCacheWhenEntityIsUpdated is disabled

Something like

if (!_options.Value.AddOrUpdateInCacheWhenEntityIsUpdated)
{
   await Cache.DeleteAsync(id).ConfigureAwait(false);
   return MapToDto(entityDbo);
}

Thank you for awesome framework!

Can't do Register Filtering Query through validation of filter query

Conditions:
using Modern.Repositories.Abstractions, Version=1.0.0.0

Stages of reproduction:

  1. Create specifications - need two or more.

new FilterByClientSpecification(x.Client),

AddFilteringQuery(x => x.Client != null
&& clients.Contains(x.Client.Name, StringComparer.Ordinal));

new FilterByCustomerSpecification(x.Customer),

AddFilteringQuery(
x => x.Customer != null && customers.Any(t => x.Customer.Contains(t, StringComparison.OrdinalIgnoreCase)));

  1. Register specifications into EfCoreSpecification

var registerSpecification = specifications.Aggregate((current, next) => current.And(next));
var efCoreSpecification = new EfCoreSpecification(registerSpecification );
4. Send a request POST with selected specifications

Expected result:
We expect filtering with selected specifications: especially if one have been chosen

Actual result:
Can't do Register Filtering Query through validation of filter query. In that method:

private void RegisterFilteringQuery(Specification left, Specification right)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.