Where to call Savechanges() when you have multiple repositories?

Asked

Viewed 312 times

6

I am developing an application with Entity Framework, with several repositories.

Each repository encapsulates SaveChanges() dbcontext.

When a business layer operation uses multiple repositories, and there is a change in the data, I need to call SaveChanges() only once.

Obviously, I can do it in any repository, but it seems strange to me to have to call one at random. What is the recommendation in this situation?

EDITED

Repositories are only on interfaces so far, there is no implementation, follow one of them

public interface IUserRepository
{
   User getByID(string ID);
   User getByIDWithActiveGlossaries(string ID);
   IEnumerable<User> getAll();

   bool Save();
}

And there are other repositories, all implementing Save(). Save is in a base interface, put together here to simplify. Save will call SaveChanges() of DbContext.

PS: I evaluated the use of UnitOfWork, but discarded, not seeing need. That’s why, alias, I call SaveChanges() at the end of a complete operation, which may involve several changes.

FINAL EDITION

I had discarded the use of Unit of Work because there was no need for a mechanism to group operations, since SaveChanges() is already "all or nothing" (all operations successfully or all are reversed).

However, thanks to the answers of Hokos and Dherik, I realized that Unit of Work not only has this functionality, but also allows grouping the operation of Save().

  • Could for an example the way your repository is done?

  • This will depend a lot on the implementation you are using, for example, if you are using dependency injection the treatment can be done through the context object that is shared between the repositories

  • @Julioborges So that’s exactly what I was going to do when I thought: Hey, I don’t want to expose Dbcontext in the business layer... then I saw that there should be a method Save() interfaces, but the question of where to save when there were several repositories in the same operation.

  • I removed my answer, I hadn’t seen your remark about discarding the Unit of Work. But it wasn’t clear to me why you dropped it. Either way, you’ll need to create the context in a single place and move to all repositories to achieve your goal, and Unit Of Work helps organize this.

  • 2

    @Dherik I dismissed Unit Of Work because I didn’t need a mechanism to ensure integrity in operations, which for me is the main reason for Unit of work: ensuring that all operations are successful, or that none is executed. But seeing your answer I thought that Unit Of Work also serves to centralize the control of Dbcontext, which is what I need. Return your answer, I will accept and edit my question to be complete.

  • @Rsinohara, I get it. At first I thought you needed the integrity of operations between repositories. I returned my answer because, even if it is not the preferred solution to your case, it can help other people with a similar problem who get to your question.

  • 2

    @Dherik I actually rethought the situation, as I mentioned in the question (I don’t know if it was the most appropriate way to put it, but I didn’t want to simply remove the mention of the Unit of Work).

  • Opa, It took me a while to see and the guys already blasted the answer, really the best is the Unit Of Work, combining this with Dependency Injection definitely meets your need.

Show 3 more comments

2 answers

5


I believe that the Pattern Unit Of Work will solve your problem.

With it, briefly, you create a working unit and add the repositories in it. At the end, you call the Commit() of the work unit.

Even if I don’t wish to share the same context between the repositories, you can use the idea of Unit of Work as the basis for the solution.

Here you can find a more complete example with multiple repositories.

1

You can change your method Save() to receive a transaction. This way you could check, if a transaction has been informed, only add the object in context and give the commit in the transaction after calling all the Save(). Another approach would be when not passing the transaction, then you could give the Savechanges right inside the method, it is implied that only one object is being saved.

public bool Save(TransactionScope transaction = null)
{
    if(transaction != null)
    {
     //Aqui você apenas adiciona o objeto no contexto.
    }
    else
    {
     //Aqui você salva direto o objeto.
    }
}

After going through the N’s Save() you will do, just give a Commit on the transaction. If you do not have N, called a Save() saved and that’s it.

  • The scenario I described is not the best to be done (in my opinion). I would not make Save() separate in each repository, I would make at most a method that "prepares" the entity to be saved and then save it with my context.

Browser other questions tagged

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