Code Monkey home page Code Monkey logo

unit-of-work-core's Introduction

UnitOfWorkCore

A standalone Unit of Work component for Entity Framework Core 2.0 and ASP.NET Core 2.0 which handles transactions automatically (in ASP.NET request scope) by committing (and rolling back in case of an error) them at the end of HTTP request. Supports multiple DbContexts.

Repository contents

This repository contains several C# projects:

  • UnitOfWorkCore - core library with Unit of Work pattern implementation
  • UnitOfWorkCore.AspNetCore - UnitOfWorkCore configuration (transaction filters and isolation level attributes) for ASP.NET Core 2.0
  • Sample projects:
    • UnitOfWorkCore.Samples.ReleasesDatabase - sample database migration scripts (console app using DbUp)
    • UnitOfWorkCore.Samples.IssuesDatabase - sample database migration scripts (console app using DbUp)
    • UnitOfWorkCore.Samples.SingleContextApi - sample ASP.NET Core 2.0 project using UnitOfWorkCore with only one DbContext
    • UnitOfWorkCore.Samples.MultiContextApi - sample ASP.NET Core 2.0 project using UnitOfWorkCore with two DbContexts

Nuget packages

UnitOfWorkCore component is distributed as two separate NuGet packages

To install UnitOfWorkCore and UnitOfWorkCore.AspNetCore in your project(s), use the Visual Studio's built-in NuGet GUI (Manage NuGet packages option in project's context menu) or run the following commands in Package Manager Console:

Install-Package UnitOfWorkCore    
Install-Package UnitOfWorkCore.AspNetCore

Single DbContext usage

Register your DbContext in ConfigureServices method in Startup.cs

services.AddDbContext<ReleasesDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ReleasesDb")));

Register UnitOfWorkCore for your DbContext in services

services.AddUnitOfWork<ReleasesDbContext>();

Add UnitOfWorkTransactionFilter to global filters

services.AddMvcCore(options =>
{      
    options.Filters.Add(typeof(UnitOfWorkTransactionFilter));
});

Inject IUnitOfWork into your services where you need to access DbSets or save database changes (like EF's DbContext.SaveChanges) to obtain inserted entity's id etc.

public ReleasesService(IUnitOfWork uow) 
{ 
    this._uow = uow;
}

Use the IUnitOfWork in your service

//add entity to the database
_uow.Set<ReleaseEntity>().Add(entity);

//save changes to obtain the entity id
_uow.SaveChanges();

PRO TIP: If you don't want to write _uow.Set<MyEntity>() with the exact name of the entity's class because you never remember it, or would like Intellisense to help you with selecting the right entities set, you can either:

A) Use helper extension methods:

public static DbSet<ReleaseEntity> Releases(this IUnitOfWork uow)
{
    return uow.Set<ReleaseEntity>();
}

//and then:
_uow.Releases().Add(entity);

B) Utilize decorator pattern described in the next section with Multiple DbContexts usage (this is a more elegant solution for multiple DbContexts, but it also works for a single one)


Multiple DbContexts usage

Register your DbContexts in ConfigureServices method in Startup.cs

services.AddDbContext<ReleasesDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ReleasesDb")));

services.AddDbContext<IssuesDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("IssuesDb")));

Register multiple UoWs, providing a unique key (string) for each of them

services.AddUnitOfWorkPool(optionsBuilder =>
{
    optionsBuilder.AddUnitOfWork<ReleasesDbContext>("Releases");
    optionsBuilder.AddUnitOfWork<IssuesDbContext>("Issues");
});

Add UnitOfWorkPoolTransactionFilter (please notice the Pool word) to global filters

services.AddMvcCore(options =>
{      
    options.Filters.Add(typeof(UnitOfWorkPoolTransactionFilter));
});

Inject IUnitOfWorkPool into your services and retrieve IUnitOfWork for a specific DbContext by its key

private readonly IUnitOfWork _releasesUow;
private readonly IUnitOfWork _issuesUow;

public MyService(IUnitOfWorkPool uowPool)
{
    _releasesUow = uowPool.Get("Releases");
    _issuesUow = uowPool.Get("Issues");
}

PRO TIP: Injecting IUnitOfWorkPool into your services and retrieving the required IUnitOfWork by key may be a bit tedious and unelegant - it would be much easier if you had a separate interface for each of your UoWs, e.g IReleasesUoW and IIssuesUoW, which you could inject instead of the whole IUnitOfWorkPool. You can easily do this by using the decorator pattern that will also allow you to extend UoW with additional methods and properties (e.g. DbSet properties for easier access to data with Intellisense, methods for bulk insert, delete etc.) See the sample code in UnitOfWorkCore.Samples.MultiContextApi project.

The general steps for the adapter are:

  1. Create an interface that inherits from IUnitOfWork<TDbContext> and add your own methods and properties
public interface IReleasesUoW : IUnitOfWork<ReleasesDbContext>
{
    DbSet<ReleaseEntity> Releases { get; }
}
  1. Implement your custom interface, inject IUnitOfWorkPool and use the IUnitOfWork retrieved by key in your methods
public class ReleasesUoW : IReleasesUoW
{
    private readonly IUnitOfWork _uow;

    public DbSet<ReleaseEntity> Releases => _uow.Set<ReleaseEntity>();

    public ReleasesUoW(IUnitOfWorkPool uowPool)
    {
        _uow = uowPool.Get("Releases");
    }

    //IUnitOfWork<ReleasesDbContext> methods
    public void CommitTransaction()
    {
        _uow.CommitTransaction();
    }

    //(...)
}
  1. Register your custom UoW in Startup.ConfigureServices and inject it into your other classes
//register in DI container
services.AddScoped<IReleasesUoW, ReleasesUoW>();

//use as a dependency in other classes instead of IUnitOfWorkPool
public MyService(IReleasesUoW uow) {}

unit-of-work-core's People

Contributors

piotrekh avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

unit-of-work-core's Issues

The transaction always comes null

Hi piotrekh

I have implemented your code to my sample project. But the transaction always comes null to the"UnitOfWorkPoolTransactionFilter". So the SaveChanges method doesn't working becasue of the transaction comes null. My code only differs from yours that my code has the value of autocommit in the TransactionIsolationLevel class.

This is screencast

https://www.screencast.com/t/dlB2O4Qqyk

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.