Small .NET library that helps to decouple database and business layers by exposing a wide range of interfaces that can be implemented using your favorite ORM, micro-ORM, ADO.NET or even all since everything is plugable and implementation can be swapped per entity.
The library is available via NuGet packages:
| NuGet | Description | Version |
|---|---|---|
| SimpleSoft.Database.Contracts | database contracts (IReadById, ICreate, IDelete, ...) | |
| SimpleSoft.Database.EFCore | Entity Framework Core implementation | |
| SimpleSoft.Database.NH | NHibernate implementation |
This library is compatible with the following frameworks:
SimpleSoft.Database.Contracts- .NET Framework 4.0+;
- .NET Standard 1.0+;
SimpleSoft.Database.EFCore- .NET Standard 1.3+;
SimpleSoft.Database.NH- .NET Framework 4.6.1+;
- .NET Standard 2.0+;
- .NET Core App 2.0+;
Here is a simple example how to setup and use within an ASP.NET Core application:
publicclassStartup{publicvoidConfigureServices(IServiceCollectionservices){services.AddDbContext<ExampleContext>(o =>o.UseInMemoryDatabase("ExampleDatabase")).AddDbContextOperations<ExampleContext>();// this line hereservices.AddMvc();}// ...}publicclassExampleContext:DbContext{publicExampleContext(DbContextOptions<ExampleContext>options):base(options){}protectedoverridevoidOnModelCreating(ModelBuilderbuilder){builder.Entity<ProductEntity>(cfg =>{cfg.MapPrimaryKey();cfg.MapExternalId();cfg.HasIndex(e =>e.Code).IsUnique();cfg.Property(e =>e.Code).IsRequired().HasMaxLength(8);cfg.Property(e =>e.Name).IsRequired().HasMaxLength(256);cfg.Property(e =>e.Price).IsRequired();});}}[Route("products")]publicclassProductsController:Controller{// either inject by constructor//private readonly IQueryable<ProductEntity> _productQuery;//private readonly IReadByExternalId<ProductEntity> _productByExternalId;//private readonly ICreate<ProductEntity> _productCreate;//public ProductsController(// IQueryable<ProductEntity> productQuery,// IReadByExternalId<ProductEntity> productByExternalId,// ICreate<ProductEntity> productCreate//)//{// _productQuery = productQuery;// _productByExternalId = productByExternalId;// _productCreate = productCreate;//}// or inject directly into each method[HttpGet("")]publicasyncTask<IEnumerable<ProductModel>>GetAll([FromServices]IQueryable<ProductEntity>productQuery,CancellationTokenct){returnawaitproductQuery.Select(p =>newProductModel{Id=p.ExternalId,Code=p.Code,Name=p.Name,Price=p.Price}).ToListAsync(ct);}[HttpGet("{id:guid}")]publicasyncTask<IActionResult>GetById([FromServices]IReadByExternalId<ProductEntity>productByExternalId,[FromRoute]Guidid,CancellationTokenct){varproduct=awaitproductByExternalId.ReadAsync(id,ct);if(product==null){returnNotFound(newErrorModel{Message=$"Product {id} not found"});}returnOk(newProductModel{Id=product.ExternalId,Code=product.Code,Name=product.Name,Price=product.Price});}[HttpPost]publicasyncTask<IActionResult>Create([FromServices]IQueryable<ProductEntity>productQuery,[FromServices]ICreate<ProductEntity>productCreate,[FromBody]CreateProductModelmodel,CancellationTokenct){if(awaitproductQuery.AnyAsync(p =>p.Code==model.Code,ct)){returnConflict(newErrorModel{Message="Duplicated product code"});}varproduct=awaitproductCreate.CreateAsync(newProductEntity{ExternalId=Guid.NewGuid(),Code=model.Code,Name=model.Name,Price=model.Price},ct);returnCreatedAtAction(nameof(GetById),new{id=product.ExternalId},newProductModel{Id=product.ExternalId,Code=product.Code,Name=product.Name,Price=product.Price});}}