Unit Of Work + Ioc + Idisposable

Asked

Viewed 1,562 times

10

I’m putting together a project that I use Uow to facilitate the issue of transactions. In some scenarios, I use several repositories, persisting the data in memory to save at once in the BD using a Commit() method of the class Unitofwork. I’m also using Entity Framework, to which I receive an Interface Idbcontext in the builder of Unitofwork and use a set of Dbset and the very Savechanges() framework to join the Commit().

Now let’s get to the question, I’m not using the interface Idisposable in Unitofwork and wanted to know if there is need since I am using Ioc (with Simpleinjector). Another point is that I have seen many articles using Idisposable in the repositories, but I am using a single instance per request, if I close the database connection and in the same request call another repository maybe release a Exception. I think what I lack is knowledge compared to this.

Iunitofwork interface:

public interface IUnitOfWork
{
    IDbSet<TEntity> Set<TEntity>() where TEntity : class;
    void Commit();
}

Unitofwork class

public class UnitOfWork : IUnitOfWork //Deveria implementar IDisposable aqui ?
{
    private readonly IDbContext _dbContext;

    public UnitOfWork(IDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return _dbContext.Set<TEntity>();
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }
}

Idbcontext interface:

public interface IDbContext
{
    IDbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

Dbcontext:

public class MeuDbContext : IDbContext
{
    public MeuDbContext() : base("MeuDbContextConnectionString") 
    {
        //Configurações ...
    }

    public DbSet<ClasseA> ClasseA { get; set; }
    public DbSet<ClasseB> ClasseB { get; set; }

    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException exception)
        {
            var ex = HandleDbEntityValidationException(exception);
            throw ex;
        }
        catch (DbUpdateException exception)
        {
            var ex = HandleDbUpdateException(exception);
            throw ex;
        }
    }
}

Ioc:

public class MeuProjetoBootstrap
{
    public static void RegisterServices(Container container)
    {
        container.Register<IDbContext, QueensberryDbContext (Lifestyle.Scoped);
        container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
    }
}

Setting:

public class MeuExemploApplication()
{
    private readonly IUnitOfWork _uow;
    private readonly IClasseARepositorio _classeARepositorio;
    private readonly IClasseBRepositorio _classeBRepositorio;

    public void MeuExemploApplication(IUnitOfWork uow, IClasseARepositorio classeARepositorio, IClasseBRepositorio classeBRepositorio) 
    {
        //Utilizacao de IoC
        _uow = uow;
        _classeARepositorio = classeARepositorio;
        _classeBRepositorio = classeBRepositorio;
    }

    public void Adicionar(DadosViewModel model)
    {
        // Deveria utilizar *using* aqui ? Algo como: 
        // using(_uow) { ... código citado abaixo ... }

        var classeA = new ClasseA()
        {
            PropriedadeUm = model.PropriedadeUmA,
            PropriedadeDois = model.PropriedadeDoisA
        }

        _classeARepositorio.Adicionar(classeA);

        var classeB = new ClasseB()
        {
            PropriedadeUm = model.PropriedadeUmB,
            PropriedadeDois = model.PropriedadeDoisB
        }

        _classeBRepositorio.Adicionar(classeB);

        _uow.Commit();

    }
}

I’m not using the interface Idisposable nowhere. Where should I close the connection to the Database ? In the Unit Of Work class ? And if so, how to do this using Ioc and without the need to call a Dispose() method for each operation.

OBS: I don’t think it’s in a repository, because if I call two repositories in a single operation, maybe the first repository called closes the connection to the database and how I’m using an instance for request this would give a problem to the following repository.

  • http://answall.com/questions/51536/quando-usar-entity-framework-com-repository-pattern/80696#80696

  • Nice... but there’s a question. In a scenario like DDD (where Eric Evans himself teaches about repositories), you think it’s bad practice even if it’s used in this question ? Is it best practice to replace the repositories with Extesions Methods ? I believe that the book was created even before C# offered resources like Extesions Methods and it is based on a tool like Java that I do not know if I have an alternative. If you could clear that up, I’d appreciate it.

  • "you think it’s bad practice even being used in this question?". Yes. You read the answer?

  • "Is it best practice to replace the repositories with Extesions Methods ? I believe the book was created even before C# offered features like Extesions Methods and it is based on a tool like Java that I don’t know if I have an alternative." The question is not about Java: it is about C# using Entity Framework. There is no Extensions for Java. There is no Entity Framework for Java. If we were talking about Java and Java repositories, there would be no problem of practices in your question. I ask you once again to re-read the answer linked to your question.

1 answer

11


I don’t know which dependency injection framework you’re using, but usually these frameworks have something called lifestyle (which you yourself showed in your code), and depending on the lifestyle, yourself container will call the Dispose() for you.

Usually they come with these possible settings:

  • Transitory (): a new instance each time it is necessary to inject the object
  • Singleton: a single instance for the application. In the case of a web application, for example, the same instance will be used for several requests (i.e., as long as the process exists).
  • By Thread: an instance per thread (I particularly never needed to use this)
  • By Request: a new instance will be used for each request, but this obviously does not work with WPF and Win Forms applications, for example.

The correct thing is to study the framework you are using and understand if it works like this, I use Ninject and I know it works like this.

Behold here a table showing how Ninject Copes work.


In the case of Ninject for the above situations, he just won’t call the Dispose() automatically for the transient, and the class that will receive the dependency should implement the IDisposable and do the resources (ex: DbContext) on its own account.

Repository Pattern + Dbcontext + Dispose where?

It is quite common to see people who are studying/learning (as I am) read about EF + Repository Pattern + Ioc + Uow, looking like this it seems like a perfect formula for a good architecture, but this is just conceptual.

In fact, to avoid complexity when working with the DbContext, the ideal is to ensure that for the execution of an action (eg: register user, approve payment, process order, release products) is used the same instance of DbContext. This is because unless you interfere with its settings, when you load a list of entities, EF, for example, creates proxy classes and already starts to notice any changes in these objects. It is intelligent to the point that if you change any objects in your graph, that is, child classes, grandchildren and so on, when you run the SaveChanges() he’ll know exactly what to do.

But some examples of Repository Pattern receive an instance of DbContext in its builder, and end up having some generic method (often in a RepositoryBase) thus:

public Repository(IDbContext db)
{
    this._db = db;
}

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

What is the need for this Attach() and that manual amendment to State of entry? Simple, this object was recovered through another instance of DbContext. If the same instance had been used, there would not have to be such a method Update(). But how will you ensure that the same instance of DbContext will be used throughout the execution of your action, until calling the SaveChanges (where appropriate)?

Ioc FTW?

Then they saw that it would be possible to solve this problem with the Ioc, where it would keep a single instance of the DbContext and would inject the same instance into different repositories. Hence there is no need to manually use Attach, Detach and neither of that Update in the repositories.

How multiple repositories can share the same DbContext, none of them should call the Dispose() from it, because how do we make sure that no one else will still need it? Will we set up a Singleton instance? It’s not exactly a good idea to keep one DbContext wandering around the application all the time (I may be wrong).

So let’s define that we only need a certain instance of DbContext until our action is executed. Actions are in the application layer, for example your method Add. The add method will use all the repositories you want to somehow call the SaveChanges and give the Dispose() in the DbContext, also ensure that this same DbContext will be used only during the execution of the actions of that application. To do this, instead of injecting repositories into the application layer, an idea would be to create a single class to take care of that single instance of DbContext which should only be used for that particular action, and it will also inject that Dbcontext into the repositories. Since this class will represent an execution of the application, let’s call it Unitofwork (work unit):

public class UnitOfWork: IDisposable
{
    public UnitOfWork()
    {
        this._db = new QueensberryDbContext();
    }

    public RepositoryA GetRepositoryA()
    {
        return new RepositoryA(_db);
    }

    public IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return _db.Set<TEntity>();
    }

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

public class MeuExemploApplication: IDisposable
{

    public MeuExemploApplication(UnitOfWork uow) 
    {
        this._uow = uow;
    }

    public void Adicionar()
    {
        var coisas = _uow.GetRepositorioA().GetAlgumaCoisa(); // por repositório
        var usuarios = _uow.Set<Usuario>().ToList(); // acessando diretamente o set
        // faz tudo o que tem que fazer no método "Adicionar"
        _uow.Commit(); // save changes
    }

    public void Dispose()
    {
        _uow.Dispose(); // dispose uow, que internamente fará dispose do DbContext
    }
}

Understand that when working with the Unitofwork, he is responsible for managing the lifetime of the DbContext, because it represents a working unit, and ideally the DbContext should be maintained only until the execution of this task/action/action (as you want to call the use cases of your application). In this case, you do not have the DbContext in its dependency injection container, and the UnitOfWork must be configured by Scope, that is, whenever an application is instantiated, a new exclusive instance for that application of UnitOfWork (which consequently will have its own DbContext) will be injected, and the application is who takes care of your exclusive UnitOfWork calling the Dispose() on its own account.

Web Applications

In the case of a web application, where Asp.net manages the entire request flow, I particularly I don’t see the slightest need to use Unitofwork. This is because each request can be understood as a work unit, then you configure the DbContext in the Ioc again, but uses the option Per Request.


I particularly agree with the Gypsy, i only use Repository Pattern in my applications as a way to encapsulate and reuse complex queries (as well as access them within the Domain), but this could be replaced by extension methods (as observed by Gypsy), nor use also the UnitOfWork, because my data access is always done through a web application (Web API or WCF), and if I ever need a WPF or Winforms, I consume the API/WCF. So until now I had no need to use the Unitofwork.

I think Repository Pattern does add a complexity, and it needs to be well analyzed if it’s worth, the link with Gypsy response is excellent. I understand that in a microservice-oriented architecture, it is unnecessary to use. But if you’re building a super API, it might be worth it, because the chances of you needing to reuse code are high.

KISS

  • 4

    Thank you, young man. I’d vote twice if I could.

  • 1

    @Ciganomorrisonmendez I thank for the link in the comments. I already saved the link to distribute to some developers friends (including the team where I work). I voted and would also vote more often!

  • 1

    Thanks man. I’m using Simple Injector and I realized that really, after running a View (MVC), it enters Dispose automatically. I was using searches through Uow, but I already refactored the code to not search for Uow because it was overloading the memory, so for any type of search I create an instance and give Ispose next (I checked that even the memory consumption of the application pool).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.