Reputation: 61
I am working with a database where I have more than 75 tables and I am using the repository and unit of work patterns with Entity Framework in an ASP.NET MVC project. I am little bit confused and some query in my mind about object creation. When UnitOfWork initializes, it creates object for all table's entity which is present in UnitOfWork. So it can be heavy for application load.
Here is the interface of unit of work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Application.Repository;
using Application.Repository.General;
namespace Application.UnitOfWorks
{
public interface IUnitOfWork : IDisposable
{
IGeneralRegionMasterRepository GeneralRegionMasters { get; }
IGeneralSubRegionMasterRepository GeneralSubRegionMasters { get; }
IGeneralCountryMasterRepository GeneralCountryMasters { get; }
IGeneralStateMasterRepository GeneralStateMasters { get; }
IGeneralCityMasterRepository GeneralCityMasters { get; }
int Complete();
}
}
Implementation:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Application.EntityFramework;
using Application.Repository;
using Application.Repository.General;
namespace Application.UnitOfWorks
{
public class UnitOfWork : IUnitOfWork
{
public readonly InventoryDbContext _context;
public UnitOfWork(InventoryDbContext context)
{
_context = context;
GeneralRegionMasters = new GeneralRegionMasterRepository(_context);
GeneralSubRegionMasters = new GeneralSubRegionMasterRepository(_context);
GeneralCountryMasters = new GeneralCountryMasterRepository(_context);
GeneralStateMasters = new GeneralStateMasterRepository(_context);
GeneralCityMasters = new GeneralCityMasterRepository(_context);
}
public IGeneralRegionMasterRepository GeneralRegionMasters { get; private set; }
public IGeneralSubRegionMasterRepository GeneralSubRegionMasters { get; private set; }
public IGeneralCountryMasterRepository GeneralCountryMasters { get; private set; }
public IGeneralStateMasterRepository GeneralStateMasters { get; private set; }
public IGeneralCityMasterRepository GeneralCityMasters { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
}
I want to know about performance effect of it on application. Thank you in advance for help.
Upvotes: 1
Views: 1659
Reputation: 990
Re:
When UnitOfWork initializes, it creates object for all table's entity which is present in UnitOfWork. So it can be heavy for application load.
You don't need to initialize all the repo instances in the UoW constructor. You can create them when they are required in the corresponding getters (lazy initialization):
private IGeneralRegionMasterRepository _generalRegionMasters;
public IGeneralRegionMasterRepository GeneralRegionMasters {
get {
if (_generalRegionMasters == null) {
_generalRegionMasters = new GeneralRegionMasterRepository(_context);
}
return _generalRegionMasters;
}
}
Upvotes: 0
Reputation: 4336
I've run into the same problem that you are describing in the past. The structure of the code just feels really heavy since you are creating new instances of 70 repositories even though you may only need one of them. This is why I've just started to avoid adding my own UoW and Repositories when using EF directly because EF already has Repositories and UoW built in (DbSets = Repos, Save Changes does UoW save at the end of all DbSet changes). If you don't want to code directly against a DbContext, just have your DbContext implement the IUnitOfWork interface directly and go off of that. Also have all your DbSets exposed on that UnitOfWork. Then you could have it also implement IMyDbContext and have that expose the DbSets and have this interface also implement IUnitOfWork (or have DbContext -> IMyDbContext -> IUnitOfWork) or break them up if you don't want repo code having access to Save at the bottom. This just ends up making it easier in the long run. No weird code to maintain, no classes to create. If you switch to not use EF, you can still use those same interfaces behind the scenes and the only thing that would have to change would be the DbSet implementation (maybe you can even get that to be generic - create your on DbSets that implement another interface, too). Personally, I'm going down the CQS path so I don't have to worry about repos or UoW anymore. :)
Edit Example the best I can here! :)
public interface IUnitOfWork
{
int Complete();
Task<int> CompleteAsync();
}
public interface IInventoryDbContext : IUnitOfWork
{
DbSet<GeneralRegionMaster> GeneralRegionMasters { get; }
DbSet<GeneralSubRegionMaster> GeneralSubRegionMasters { get; }
... etc
}
public class MyDbContext : DbContext, IInventoryDbContext
{
public DbSet<GeneralRegionMaster> GeneralRegionMasters { get; set; }
public DbSet<GeneralSubRegionMaster> GeneralSubRegionMasters { get; set;
}
public int Complete() => this.SaveChanges();
public Task<int> CompleteAsync() => this.SaveChangesAsync();
}
If you did a controller level only:
public class MyController : Controller
{
private readonly IInventoryDbContext _context;
public MyController(IInventoryDbContext context)
{
_context = context;
}
public JsonResult CreateGeneralRegionMaster(GeneralRegionMaster entity)
{
_context.GeneralRegionMaster.Add(entity);
var result = _context.Complete();
return Json(result == 1);
}
}
Again, you could do something different for the DbSets and do this instead:
public interface IRepo<T> where T: class
{
// Expose whatever methods you want here
}
public class MyDbSet<T> : DbSet<T>, IRepo<T> where T: class
{
}
Then this changes:
public interface IInventoryDbContext : IUnitOfWork
{
IRepo<GeneralRegionMaster> GeneralRegionMasters { get; }
IRepo<GeneralSubRegionMaster> GeneralSubRegionMasters { get; }
... etc
}
public class MyDbContext : DbContext, IInventoryDbContext
{
public MyDbSet<GeneralRegionMaster> GeneralRegionMasters { get; set; }
public MyDbSet<GeneralSubRegionMaster> GeneralSubRegionMasters { get; set; }
public IRepo<GeneralRegionMaster> GeneralRegionMastersRepo => GeneralRegionMasters;
public IRepo<GeneralSubRegionMaster> GeneralSubRegionMastersRepo => GeneralSubRegionMasters;
public int Complete() => this.SaveChanges();
public Task<int> CompleteAsync() => this.SaveChangesAsync();
}
Upvotes: 2