Backend/.NET

Generic Pattern - Unit of Work Pattern

Jin-Co 2023. 5. 16. 10:48
반응형

The generic pattern allows us to use the same method for a different set of entities. However, it also creates a problem that related entities are partially updated which will lead to an error not to mention that we have to inject each entity separately.

 

To solve this problem, we will see another pattern called the unit of work.

List of Contents

Setting Up a Project

 

Creating a WepAPI

 

How to create .NET web-API

Setting up development tools When working with .NET, we need tools to create a web application. We can download them at the link below. .NET | Free. Cross-platform. Open Source. (microsoft.com) .NET | Free. Cross-platform. Open Source. .NET is a developer

jin-co.tistory.com

Setting Up the Generic Pattern

 

Application Architecture - Generic Repository

The repository pattern has a static type so whenever we create an entity, we have to create a repository as well. A generic is a way to restrict to a type or to dynamically change types. Let's see how we can use a generic repository for multiple entities P

jin-co.tistory.com

Implementation

Adding a Work Unit Interface

Create a class file to use as an interface

Inherit from the 'IDisposable' interface (This interface makes sure components are disposed of after use). Then add an array to store the status of each entity.

Implementing the Work Unit Interface

Create another class to implement the interface

Add a constructor and inject the context. Add a private hash table field to manage the status of repositories.

private readonly StoreContext _context;
private Hashtable _repos;
public WorkUnit(StoreContext context)
{
  this._context = context;
}

Update the implemented method with the code shown below.

public async Task<int> Completed()
{
  return await _context.SaveChangesAsync();
}

public void Dispose()
{
  _context.Dispose();
}

public IGenericRepo<T> Repo<T>() where T : BaseEntity
{
  if (_repos == null) _repos = new Hashtable();
  var type = typeof(T).Name;
  if (!_repos.ContainsKey(type))
  {
    var repoType = typeof(GenericRepo<>);
    var repoInstance = Activator.CreateInstance(repoType.MakeGenericType(typeof(T)), _context)
    _repos.Add(type, repoInstance);
  }
  return (IGenericRepo<T>)_repos[type];
}

Registering the Work Unit Interface

Go to the Program.cs file and add the interface as a service.

builder.Services.AddScoped<IWorkUnit, WorkUnit>();

Adding Methods to Manage Entities' Status

Go to the generic interface and add methods to manage the status of entities.

void Add(T entity);
void Update(T entity);
void Delete(T entity);

Move to the implementing class and update the implementation. Update the methods with the code shown below. Basically, the Add method will add entities but not save changes until we call the Complete

public void Add(T entity)
{
  _context.Set<T>().Add(entity);
}

public void Delete(T entity)
{
  _context.Set<T>().Remove(entity);
}

public void Update(T entity)
{
  _context.Set<T>().Attach(entity);
  _context.Entry(entity).State = EntityState.Modified;
}

Updating the Controller

Go to the controller file

Before

Delete the generic injection for each entity and inject the unit of the work interface.

After

Updating Data in the Database

As I mentioned above we do not update the data until we are done and call the Complete method. So if there is an error in updating one of the entities the data won't be updated at all in its entity

We have seen how we can update the generic pattern with the unit of work pattern. The unit of work pattern fills a hole in the generic pattern by linking entities to a unit that works in a linear manner without sacrificing the type flexibility of the generic pattern.

 

728x90
반응형