Skip to content

ScopedUnitOfWork is a lightweight .NET Standard implementation of Unit of Work and Repository patterns, extended with scoped functionality to improve read performance and in-built with transactions management; in respect to underlying Entity Framework Core ORM.

License

Notifications You must be signed in to change notification settings

LuanNg/ScopedUnitOfWork

 
 

Repository files navigation

ScopedUnitOfWork

ScopedUnitOfWork is a lightweight .NET Standard implementation of commonly used Unit of Work and Repository patterns, extended with scoped functionality to improve read performance and in-built with transactions in respect to underlying Entity Framework Core ORM.

Three key features are:

  • very simple and extensible repository / uow implementation, which integrates with any IoC container out there
  • scoped (ambient) contexts
  • scoped (ambient) transactions

Simple extensible repository / uow implementation

Altough there are about a milion other repository / uow implementations, I never found any that was simple enough, without the bloat of 100s of methods, that was IoC / DI friendly and that was easily extensible (essentially respecting the open / closed principle).

A pattern that worked for me for years is having a injectable factory, which creates units of work, which are then used to resolve the repositories. Something like:

using (IUnitOfWork unitOfWork = factory.Create())
{
    unitOfWork.GetRepository<ICustomerRepository>().Add(...);
    unitOfWork.Commit();
}

What I also needed is that the framework uses the underlying IoC container, for example when resolving repositories like in example above. This removes any need of having concrete repository properties on UnitOfWork class which is a common anti-pattern.

Scoped contexts

Main reason for scoped / ambient contexts is usage of so called L1 cache. This is the in-built cache in the EFCore DbContext which is checked when retriving entities by the identifier (for example when using context.Find()). To take advantage of this caching you simply reuse the same database context for multiple operations. But, as soon as you start "sharing" these context you have to manage their lifecycles as well. There are many patterns to go about this issue, session-per-web-request or session-per-controller to just name a few. I would strongly recommend reading this excellent acricle for more info: http://mehdi.me/ambient-dbcontext-in-ef6/

How does scoped units of work look like? Like this:

using (IUnitOfWork parent = factory.Create())
{
    using (IUnitOfWork child = factory.Create())
    {
        ...
    }
}

Scoped / ambient functionality takes care that both parent and child have actually the same DbContext instance.

Scoped / ambient transactions

Very similarly to the scoped contexts, this library offers easy to use Transaction management. Here is an example:

using (IUnitOfWork unitOfWork = factory.Create(ScopeType.Transactional))
{
    // everything here, as well as any other unit of work are now transactional
    using (IUnitOfWork unitOfWork = factory.Create())
    {
        ...
    }

    // commits everything
    unitOfWork.Commit();
}

Setup

TODO

About

ScopedUnitOfWork is a lightweight .NET Standard implementation of Unit of Work and Repository patterns, extended with scoped functionality to improve read performance and in-built with transactions management; in respect to underlying Entity Framework Core ORM.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%