2

I am working on a project with Entity Framework where i have implemented Repository pattern and DI (Microsoft Unity), now to maintain the database transactions i want to implement the UnitOfWork pattern, but i am totally confused about how shall i implement it in my current project, i google around few posts, but could not find anything doable with my existing project.

Below is the EF and Repository structure along with DI (Microsoft Unity).

Entities:

public class GenericDo 
        {
            public DateTime CreatedDate {get;set;}
            public string CreatedBy {get;set;}
        }
    public class UsersDo : GenericDo
        {
            public int UserId {get;set;}
            public string Username {get;set;}
            ....
        }
    public class UserProfileDo : GenericDo
        {
            public int Id {get;set}
            public int UserId {get;set;}
            public string Address {get;set;}
            ....
        }

Interface:

public interface IGenericDao : IGenericDao<GenericDo> {}
    public interface IGenericDao<T> 
    {
        void Add(T entity);
        T Get(object Id);
        ....
    }
public interface IUsersDao : IUsersDao<UsersDo> {}
public interface IUserProfileDao : IUserProfileDao<UserProfileDo>{}

Interface Implementation:

public class GenericDao<T> : IGenericDao<T> where T : class
        {
            private readonly DataContext context;
            public GenericDao(DataContext _context)
            {
                this.context = _context;
            }
            public void Add(T entity)
            {
                context.Set<T>().Add(entity);
            }
            public T Get(object Id)
            {
                return context.Set<T>().Find(Id);
            }
        }
    public class UsersDao : GenericDao<UsersDo>, IUsersDao
        {
            public UsersDao(DataContext context) : base (context){}
        }
    public class UserPorfileDao : GenericDao<UserProfileDo>, IUserProfileDao
        {
            public UserPorfileDao(DataContext context) : base (context){}
        }

Dependency Injection Setup in Global.asax.

var container = this.AddUnity();
    container.RegisterType<IUsersDao, UsersDao>();
    container.RegisterType<IUserProfileDao, UserProfileDao>();

Now in my main webpage(ASP.Net)

public partial class Default : System.Web.UI.Page
    {
        private readonly IUsersDao usersDao;
        private readonly IUserProfileDao userProfileDao;
        public Default(IUsersDao _userDao, IUserProfileDao _userProfileDao)
        {
            this.usersDao = _userDao;
            this.userProfileDao = _userProfileDao;
        }
        // Now for testing purpose, i update record.
        protected void Page_Load(object sender, EventArgs e)
        {
            UsersDo user = usersDao.Get(1);
            user.Username = "new system";

            UserProfileDo userProfile = userProfileDao.Get(1);
            userProfile.Address = "new address";

            // Now here i am confused about setting up common Save method to update database with transaction.
        }
    }
Abbas
  • 4,948
  • 31
  • 95
  • 161
  • [This](https://stackoverflow.com/a/51781877/5779732) answer discusses about generic repository. But some points are also valid for UoW. – Amit Joshi Jan 10 '19 at 15:38

3 Answers3

3

EntityFramework's DbContext already implements Unit of Work, so it is not necessary to add yet another layer of abstraction to implement this.

One could even doubt if creating a Repository pattern is actually helpful if you're using Entity Framework. Instead of using a layered architecture and using a Repository, you could investigate whether it is not better to use a more sliced architecture and use the DbContext directly.

Also, what is the benefit of having a 'Generic Dao' that just delegates calls to Entity Frameworks DbContext ? It's just yet another level of abstraction which adds extra complexity but doesn't give you any added value.

Frederik Gheysels
  • 56,135
  • 11
  • 101
  • 154
  • GenericDao is inherited in all of my repositories, so all the common functionalities, like add,update,delete,get,list are automatically implemented across all repositories. – Abbas Jan 10 '19 at 14:00
  • 1
    @Abbas which isn't needed at all since that functionality is provided by EF's DbContext and DbSet. Adding your own "generic" methods makes it *harder* to implement UoW or use the ORM efficiently. A repository whose methods only delegate to the ORM isn't very useful. A *useful* repository would have methods like eg `Basket.AddProductToOrder` that will modify all related entities. – Panagiotis Kanavos Jan 10 '19 at 14:07
  • Microsoft says: DbContext is a combination of the Unit Of Work and Repository patterns. See this link: https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.dbcontext?view=efcore-5.0 Why thay say that DbContext follows the repository pattern? – Boris Makhlin May 27 '21 at 14:31
0

Unit of work ecapsulates the database operations in a single object and keeps track of them. In Entity Framework DbContext implements this behaviour and DbSet<> implements the repository. The reason why people create their own wrappers around is to be able to swap Entity Framework for another ORM, if needed or to mock Entity Framework for testing,.

Georgi Georgiev
  • 3,854
  • 5
  • 29
  • 39
  • could you please give me an example of how i shall be using the DbSet<> in current scenario to handle transactional update to the database. – Abbas Jan 10 '19 at 14:02
  • 1
    @Abbas you don't need to. `SaveChanges` uses a transaction internally. – Panagiotis Kanavos Jan 10 '19 at 14:02
  • So you mean, i shall have the context.SaveChanges() within my GenericDao implementation under each insert,updates and deletes? – Abbas Jan 10 '19 at 14:03
  • @Abbas quite the opposite. Remove your GenericDao and most definitely *don't* call `SaveChanges` after every change to the entities. Make a *single* `SaveChanges` call at the end of your MVC action and you have your UoW without any additional effort - `SaveChanges` will persist all changes in a single transaction. Until that point, no modifications were made to the database. – Panagiotis Kanavos Jan 10 '19 at 14:05
  • @Abbas no you need a IUnitOfWork Interface with SaveChanges method. The implementation should delegate to DbContext.SaveChanges() – Georgi Georgiev Jan 10 '19 at 14:06
  • Actually i am not using MVC, i am using ASP web application, here i am using ctr injection that provides me a new object, so i don't have the dbContext object directly available inside my web page code behind. – Abbas Jan 10 '19 at 14:07
  • @Abbas doesn't matter. No matter how you inject your repository, it should perform meaningful work. When the request complets, your web forms application should tell it to complete, save, whatever in which case it should call `SaveChanges`. In fact, you should probably think about a *service*, not a repository, eg a BasketService that creates a context, modifies products etc and finally saves the changes – Panagiotis Kanavos Jan 10 '19 at 14:09
  • It does not matter if you use MVC or not, EF is a library on its own, you could use it in a console app as well. If you use EF you have a context somewhere. You need to implement one to use it. – Georgi Georgiev Jan 10 '19 at 14:09
  • Thanks for the suggestion, if you could update my question with the necessary changes as you suggested, would be very helpful, about the `service` implementation and `SaveChanges()` – Abbas Jan 10 '19 at 14:11
  • Actually since i am injecting via ctr, my each interface will be returned with new instance of DbContext, since i am passing it to the GenericDao, hence for UsersDao and UserProfileDao, i will be having separate instance of the DbContext. – Abbas Jan 10 '19 at 14:17
0

UnitOfWork pattern is used with Entity Framework.

The repository and unit of work patterns are intended to create an abstraction layer between the data access layer and the business logic layer of an application. Implementing these patterns can help insulate your application from changes in the data store and can facilitate automated unit testing or test-driven development (TDD).

First step is to create repositories. Repository is a class which exposes methods to business layer

Second step: You can create UnitOfWork implementation as shown below. There are properties corresponding to every repository. Then you inject Unit of Work in your business layer to use the repository methods.

public class UnitOfWork : IDisposable
{
    private SchoolContext context = new SchoolContext();
    private GenericRepository<Department> departmentRepository;
    private GenericRepository<Course> courseRepository;

    public GenericRepository<Department> DepartmentRepository
    {
        get
        {

            if (this.departmentRepository == null)
            {
                this.departmentRepository = new GenericRepository<Department>(context);
            }
            return departmentRepository;
        }
    }

}

refer documentation at: https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

Manoj Choudhari
  • 5,277
  • 2
  • 26
  • 37
  • In future if i want to add new Repository then? will i have to add new Prop in UnitOfWork class. – Abbas Jan 10 '19 at 14:36
  • You can create collection of BaseRepositories inside UnitOfWork class. Alternatively you can create [generic UnitOfWork](https://medium.com/@utterbbq/c-unitofwork-and-repository-pattern-305cd8ecfa7a) and that would work with any repository. – Manoj Choudhari Jan 10 '19 at 14:54