Is there a recommended base repository class to use with Entity Framework? - asp.net-mvc-3

I'm using an EF Code First approach with an ASP.NET MVC 3 application, and instead of re-creating the wheel, I was wondering if there already exists a solid base Repository class that my custom Repository classes could extend in order to provide default functionality out of the box (e.g. basic CRUD, etc...).
So something like this ...
public class CustomerRepository : BaseRepository { ... }
... would therefore provide a default way to work with Customer objects out of the box. I'd like to then inject an ICustomerRepository into my MVC controllers and have the functionality available to me there.
I'm sure something like this already exists out there as I've done something similar with NHibernate.
Thanks

No, there is no built-in repository, other than EF itself (which is in and of itself an implementation of the Unit of Work pattern, and DbSet's are basically Repositories).
There is currently a debate in the software community over whether generic repositories have much real value. For testing purposes, many argue, they provide easy unit testing. Others say that unit testing repositories doesn't help because mocked repositories don't behave the same way that real ones do (because of the linq -> Sql translation layer, which doesn't exist in a mocked repository).
Many are suggesting that you do integration testing against EF using an in-memory database like SqlLite rather than unit testing it.
Still, if you are intent on using repositories, there are many examples out there on the net, with varying styles and methods. Or you can roll your own. MS does not provide one.

In my experience, write your own repositories is redundant because EF implements this pattern already through DbSet's.
I worked with MVC3 + EF Code Fisrt in a recent project. We started implementing a generic repository following some tutorials and soon we realized that we are writing a lot of unnecessary and redundant code. Actually, the repositories were given us nothing but hiding a lot of the DbSet's functionality. Finally, we decided to remove them and work with our DbContext and DbSet's directly.
But, how about complex business logic beyond simple CRUD operations?
Well, we exposed all complex functionality like queries and multiple CRUD operations through a service layer. You can build different service classes by functionality. By example, you can write an AccountService to manage all functionality related with user accounts. Something like this:
public class AccountService {
private MyContext ctx;
public AccountService(DbContext dbContext) {
this.ctx = (MyContext)dbContext;
}
/// <summary>
/// Gets the underlying DbContext object.
/// </summary>
public DbContext DbContext {
get { return ctx; }
}
/// <summary>
/// Gets the users repository.
/// </summary>
public DbSet<User> Users {
get {return ctx.Users;}
}
public bool ValidateLogin(string username, string password) {
return ctx.Users.Any(u => u.Username == username && u.Password == password);
}
public string[] GetRolesForUser(string username) {
var qry = from u in ctx.Users
from r in u.Roles
where u.Username == username
select r.Code;
return qry.ToArray<String>();
}
public User CreateUser(string username, string password) {
if (String.IsNullOrWhiteSpace(username)) throw new ArgumentException("Invalid user name");
if (String.IsNullOrWhiteSpace(password)) throw new ArgumentException("Invalid password");
User u = new User {
Username = username.Trim().ToLower(),
Password = password.Trim().ToLower(),
Roles = new List<Role>()
};
ctx.Users.Add(u);
ctx.SaveChanges();
return u;
}
How about dependency injection?
Using this approach, the only thing we need to inject is the DbContext. The service classes has a constructor that takes a DbContext. So, when your controller constructor takes a service instance the DbContext will be injected to it.
Edit: Example code
This is an example code about how you controller could look:
public class HomeController : Controller {
private readonly AccountService accountService;
public AccountController(AccountService accountService) {
this.accountService = accountService;
}
}
And this could be the DI configuration using NInject:
private static void RegisterServices(IKernel kernel) {
kernel.Bind<MyContext>().ToSelf().InRequestScope();
kernel.Bind<DbContext>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());
}
How about unit testing?
You could build specific interfaces for each service layer class and mock it where you need.

A friend of mine, Sacha Barber wrote a nice article covering some of these ideas.
Link can be found here.
RESTful WCF / EF POCO / Unit of Work / Repository / MEF: 1 of 2

EF has a base class called DbContext. You can add properties of type DbSet<TEntity>
This allows you to do something like this:
public class User {
public int Id { get; set; }
public string Name { get; set; }
}
public class DatabaseContext : DbContext {
public DbSet<User> Users { get; set; }
}
You can now use this like so:
using(var db = new DatabaseContext()) {
User jon = new User {Name = "Jon Smith"};
db.Users.Add(jon);
db.SaveChanges();
var jonById = db.Users.Single(x => x.Id == 1);
}
If you want more abstraction see this post about building a generic repository around EF Entity Framework 4 CTP 4 / CTP 5 Generic Repository Pattern and Unit Testable Just to note, this level of abstraction is not always needed. You should decide if your abblication will truly benefit from adding a generic repository over just using DbContext directly.

Related

How to Moq a service in a controller which use unitofwork with generic repository

I am a newbie in TDD (Asp.net MVC3 environment) and trying to adopt TDD as our better better development approach.
In our production code,we have a following scenario
In web
//Autofac used to resolve Dependency
TestController(XService xSerivice,YSerivice yService)
{_xService =xService,_YService= yService}
[HTTPPost]
ActionResult Create(A1 a1)
{
_xService.XUnitOfWork.A1.add(a1)
_xService.XUnitOfwork.SaveChanges();
}
// where X, Y are different context,Concrete class, no interface implemented!
In Business Layer
Xservice(XUnitofWork) // no interface implemented!
In DAL Layer
'XUnitofWork:DataRepostory(Generic)...
{
GenericRepository<a1Entity> A1,
GenericRepository<a2Entity> A2
}
Now I realize that we should implement interface both in our BAL and Web layer.
My question is are there any way i can mock the services(XService,YService) in our controller to test some behavior (TDD) [for example save change exception occur while saving a entity via' _xService.XUnitOfwork.SaveChanges()'?
Please help.Thanks in Advance!
If you mark members (properties, methods) in your concrete class as virtual, I think you may be able to just mock those methods / properties individually. (I think the VB equivalent of virtual is Overridable..?)
Moq works by creating a new concrete implementation of something at runtime when your test runs. This is why it works so well with interfaces and abstract classes. But if there is no interface or abstract class, it needs to override a method or property.
Reply to question author's answer:
Since you are a self-proclaimed TDD newbie, I just wanted to point out that adding a parameterless constructor to a class just for the sake of making the class testable should not be an acceptable solution.
By giving your GenericRepository class a hard dependency on Entity Framework's DbSet / IDbSet, you are creating a tight coupling between your repository implementation and EF... note the using System.Data.Entity line at the top of that file.
Any time you decide to add a constructor dependency, you should seriously consider adding it as an interface or abstract class. If you need access to members of a library which you do not control (like EF's DbContext), follow Morten's answer and wrap the functionality in your own custom interface.
In the case of DbContext, this class does more than just provide you with a UnitOfWork implementation. It also provides you a way of querying out data and adding / replacing / removing items in your repository:
public interface IUnitOfWork
{
int SaveChanges();
}
public interface IQuery
{
IQueryable<TEntity> GetQueryable<TEntity>() where TEntity : class;
}
public interface ICommand : IQuery
{
void Add(object entity);
void Replace(object entity);
void Remove(object entity);
}
You can pretty easily wrap DbContext in these 3 interfaces like so:
public class MyCustomDbContext : DbContext, IUnitOfWork, ICommand
{
// DbContext already implements int SaveChanges()
public IQueryable<TEntity> GetQueryable<TEntity>() where TEntity : class
{
return this.Set<TEntity>();
}
public void Add(object entity)
{
this.Entry(entity).State = EntityState.Added;
}
public void Replace(object entity)
{
this.Entry(entity).State = EntityState.Modified;
}
public void Remove(object entity)
{
this.Entry(entity).State = EntityState.Deleted;
}
}
Note how your interfaces take no dependencies on System.Data.Entity. They use primitives and standard .NET types like object, IQueryable<T>, and int. This way, when you give your generic repository dependencies on the interfaces, you can remove the dependency on System.Data.Entity:
// using System.Data.Entity; // no need for this dependency any more
public class GenericRepository
{
private readonly ICommand _entities;
private readonly IQueryable<TEntity> _queryable;
public GenericRepository(ICommand entities)
{
this._entities = entities;
this._queryable = entities.GetQueryable<TEntity>();
}
//public GenericRepository()
//{
// no need for a parameterless constructor!
//}
}
...and your GenericRepository is now fully unit testable, since you can easily mock any of these interface methods.
Final Notes:
Also, after seeing your answer to your own question, it looks like you have CompanyRepository as a property of your UnitOfWork class. You then inject UnitOfWork as a dependency on your CompanyInformationController. This is backwards. Instead, you should be injecting the CompanyRepository (or its interface) into the controller's constructor. The UnitOfWork pattern has nothing to do with maintaining references for your known repositories. It is about tracking multiple changes made to related items so that they can all be pushed once as a single transaction. EF does this automatically, so as long as AutoFac is providing the same DbContext instance no matter whether your app requests an IQuery, ICommand, or IUnitOfWork implementation, then the only method UnitOfWork should be concerned with is SaveChanges().
thanks for your reply. The test I was trying to do was successful after spending few hours and changes my previous code.
Changes are follows:
1) Now using UnitofWork in my controller instead of a redundant service.
2) Added a parameter less constructor to the GenericRepository Class.(with out any DBContext!),because it will requied a DBContext as a parameter in Constructor,which can not be substituted by supplying a Mocked DBContext.
GenericRepository:
public class GenericRepository where TEntity : class
{
internal DbContext _context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this._context = context;
this.dbSet = context.Set<TEntity>();
}
public GenericRepository() //newly added!
{
}
...............
Complete Test
[TestMethod]
public void Index_Return_OneModel_WhenCalling()
{
//arrange
AutoMapperExtension automapper = new AutoMapperExtension();
var moqentities = new Mock<SetupEntities>();
List<CompanyInformation> list =new List<CompanyInformation>();
list.Add(new CompanyInformation{ CompanyName = "a", CompanyAddress = "aa", Id = 1});
list.Add(new CompanyInformation { CompanyName = "b", CompanyAddress = "b", Id = 2 });
var unitOfWork = new Mock<UnitOfWork>(moqentities.Object);
unitOfWork.Setup(d => d.CompanyRepository).Returns(new GenericRepository<CompanyInformation>());
unitOfWork.Setup(d => d.CompanyRepository.GetAll()).Returns(list.AsQueryable());
var controller = new CompanyInformationController(unitOfWork.Object);
//Act
var result =(ViewResult) controller.Index();
var model =(CompanyInformationViewModel) result.ViewData.Model;
//Assert
Assert.AreEqual(1, model.Id);
}
The best way is to create an interface for XService. If that is not possible for some reason (if XService is a third party class that doesn't implement an interface), then consider wrapping the functionality in a wrapperclass that does have an interface.

Unit testing MVC controllers that use NHibernate, with and without implementing a repository pattern

I have an MVC app that uses NHibernate for ORM. Each controller takes an ISession construction parameter that is then used to perform CRUD operations on domain model objects. For example,
public class HomeController : Controller
{
public HomeController(ISession session)
{
_session = session;
}
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _session.CreateCriteria<Survey>()
.Add( Expression.Like("Name", "Sm%") )
.Add( Expression.Between("EntryDate", minDate, maxDate) )
.AddOrder( Order.Desc("EntryDate") )
.SetMaxResults(10)
.List<Survey>();
// other logic that I want to unit test that does operations on the surveys variable
return View(someObject);
}
private ISession _session;
}
I would like to unit test this controller in isolation, without actually hitting the database, by mocking the ISession object using Moq or RhinoMocks. However, it is going to be very difficult to mock the ISession interface in the unit test, because it is being used via a fluent interface that chains a number of calls together.
One alternative is to wrap the ISession usage via a repository pattern. I could write a wrapper class something like this:
public interface IRepository
{
List<Survey> SearchSurveyByDate(DateTime minDate, DateTime maxDate);
}
public class SurveyRepository : IRepository
{
public SurveyRepository(ISession session)
{
_session = session;
}
public List<Survey> SearchSurveyByDate(DateTime minDate, DateTime maxDate)
{
return _session.CreateCriteria<Survey>()
.Add( Expression.Like("Name", "Sm%") )
.Add( Expression.Between("EntryDate", minDate, maxDate) )
.AddOrder( Order.Desc("EntryDate") )
.SetMaxResults(10)
.List<Survey>();
}
private ISession _session;
}
I could then re-write my controller to take an IRepository constructor argument, instead of an ISession argument:
public class HomeController : Controller
{
public HomeController(IRepository repository)
{
_repository = repository;
}
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _repository.SearchSurveyByDate(minDate, maxDate);
// other logic that I want to unit test that does operations on the surveys variable
return View(someObject);
}
private IRepository _repository;
}
This second approach would be much easier to unit test, because the IRepository interface would be much easier to mock than the ISession interface, since it is just a single method call. However, I really don't want to go down this route, because:
1) It seems like a really bad idea to create a whole new layer of abstraction and a lot more complexity just to make a unit test easier, and
2) There is a lot of commentary out there that rails against the idea of using a repository pattern with nHibernate, since the ISession interface is already a repository-like interface. (See especially Ayende's posts here and here) and I tend to agree with this commentary.
So my questions is, is there any way I can unit-test my initial implementation by mocking the ISession object? If not, is my only recourse to wrap the ISession query using the repository pattern, or is there some other way I can solve this?
Oren tends to wander around a lot. He used to be a huge proponent of Repositories and Unit of Work. He will probably swing back around again to it, but with a different set of requirements.
Repository has some very specific advantages that none of Oren's comments have quite found solutions for. Also, what he recommends has it's own set of limitaitons and problems. Sometimes I feel like he's just exchanging one set of problems for another. It's also good when you need to provide different views of the same data, such as a Web Service, or Desktop application while still keeping the web app.
Having said that, he has a lot of good points. I'm just not sure there are good solutions for them yet.
Repository is still very useful for highly test driven scenarios. It's still useful if you don't know if you will stick with a given ORM or persistence layer and might want to swap it out with another one.
Oren's solution tends to couple nHimbernate more tightly into the app. That may not be a problem in many situations, in others it might be.
His approach of creating dedicated query classes is interesting, and is sort of a first step to CQRS, which might be a better total solution. But Software development is still so much more art or craft than science. We're still learning.
Rather than mocking out ISession have you considered having your tests inherit from a base fixture that makes use of SQLite?
public class FixtureBase
{
protected ISession Session { get; private set; }
private static ISessionFactory _sessionFactory { get; set; }
private static Configuration _configuration { get; set; }
[SetUp]
public void SetUp()
{
Session = SessionFactory.OpenSession();
BuildSchema(Session);
}
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var cfg = Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.SQLiteConfiguration.Standard.ShowSql().InMemory())
.Mappings(configuration => configuration.FluentMappings.AddFromAssemblyOf<Residential>())
.ExposeConfiguration(c => _configuration = c);
_sessionFactory = cfg.BuildSessionFactory();
}
return _sessionFactory;
}
}
private static void BuildSchema(ISession session)
{
var export = new SchemaExport(_configuration);
export.Execute(true, true, false, session.Connection, null);
}
[TearDown]
public void TearDownContext()
{
Session.Close();
Session.Dispose();
}
}
Introducing repositories with named query methods does not add complexity to your system. Actually it reduces complexity and makes your code easier to understand and maintain. Compare original version:
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _session.CreateCriteria<Survey>()
.Add(Expression.Like("Name", "Sm%"))
.Add(Expression.Between("EntryDate", minDate, maxDate))
.AddOrder(Order.Desc("EntryDate"))
.SetMaxResults(10)
.List<Survey>();
// other logic which operates on the surveys variable
return View(someObject);
}
Frankly speaking all my memory slots where already occupied BEFORE I got to the actual logic of your method. It takes time for reader to understand which criteria you are building, what parameters are you passing and which values are returned. And I need to switch contexts between lines of code. I start thinking in terms of data access and Hibernate, then suddenly I'm back to the business logic level. And what if you have several places where you need to search surveys by date? Duplicate all this staff?
And now I'm reading version with repository:
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _repository.SearchSurveyByDate(minDate, maxDate);
// other logic which operates on the surveys variable
return View(someObject);
}
It takes me zero efforts to understand what happening here. This method has single responsibility and single level of abstraction. All data access related logic gone. Query logic is not duplicated in different places. Actually I don't care how it is implemented. Should I care at all, if main goal of this method is some other logic?
And, of course, you can write unit test for your business logic with no efforts (also if you are using TDD repository gives you ability to test your controller before you actually write data access logic, and when you will start writing repository implementation, you will have already designed repository interface):
[Test]
public void ShouldDoOtherLogic()
{
// Arrange
Mock<ISurveryRepository> repository = new Mock<ISurveryRepository>();
repository.Setup(r => r.SearchSurveyByDate(minDate, maxDate))
.Returns(surveys);
// Act
HomeController controller = new HomeController(repository.Object);
ViewResult result = controller.Index(minDate, maxDate);
// Assert
}
BTW In-memory database usage is good for acceptance testing, but for unit-testing I think its an overkill.
Also take a look at NHibernate Lambda Extensions or QueryOver in NHibernate 3.0 which use expressions to build criteria instead of strings. Your data access code will not break if you rename some field.
And also take a look on Range for passing pairs of min/max values.

Ninject Binding Issue with Constructor Chaining

I have a MVC3 project that uses the Entity Framework and Ninject v2.2, and follows the Unit of Work pattern with a Service Layer wrapping my repositories.
After looking at the code below, hopefully its apparent that Ninject is using constructor chaining to inject the correct classes. It currently works prefectly in my application, however I am at the point that I need to bind an instance of IDatabase to MyDatabase with a different scope such as InSingletonScope() or InNamedScope(), not InRequestScope(). I know that I can use the [Named("MyDatabaseScope")] Attribute to customize which IDatabase object is injected, however it seems that with my code structure, if I wanted to inject my SingletonScoped instance, I would have to recreate a new Abstract and Concrete Implementation of my Unit of Work, my Service and all my Repositories, that will then chain down.
Basically my application currently goes
Controller -> Unit of Work -> Database, (Repositories -> Database)
If I have to change my Database Binding, I will now have to create another chain in addition to the current one:
Controller -> New Unit of Work -> SingletonDatabase, (New Repositories-> SingletonDatabase)
This seems to completely defeat the DRY principal. Is there a way to, from the Controller Constructor, inform Ninject that when doing constructor chaining it should use my singleton (or named binding) rather than my request scope binding, without having to recreate all my classes with a Named attribute, or a new Interface?
Sorry for the long text, I wasnt sure if I could get the point across without my code snippets and my somewhat rambling explaination.
Ninject Module Load Function:
..snip..
Bind<IUserServices>().To<UserServices>();
Bind<IBaseServices>().To<BaseServices>();
Bind<IUserRepository>().To<UserRepository>();
Bind(typeof (IRepository<>)).To(typeof (RepositoryBase<>));
Bind<IUnitOfWork>().To<UnitOfWork>();
Bind<IDatabase>().To<MyDatabase>().InRequestScope();
//This is my problem:
//Bind<IDatabase>().To<MySingletonDatabase>().InSingletonScope();
Unit of Work Implementation Constructor:
public class UnitOfWork : IUnitOfWork
{
private IDatabase _database;
public UnitOfWork(IDatabase database,
IUserRepository userRepository,
IPeopleRepository peopleRepository,
)
{
this._database = database;
this.UserRepository = userRepository;
this.PeopleRepository = peopleRepository;
}
protected IDatabase Database
{
get { return _database; }
}
...snip...
}
User Service Layer Implementation Constructor:
public class UserServices : BaseServices, IUserServices
{
private IUnitOfWork _uow;
public UserServices(IUnitOfWork uow)
: base(uow)
{
_uow = uow;
}
...snip...
}
User Repository Constructor:
public class UserRepository : RepositoryBase<User>, IUserRepository
{
public UserRepository(IDatabase database)
: base(database)
{
}
...snip...
}
Controller Constructor:
public IUserServices _userServices { get; set; }
public ActivityController(IUserServices userServices)
{
_userServices = userServices;
}
}
Using Ninject 3.0.0 you can use WhenAnyAncestrorNamed("Some name") But if you need to run asyncronous things you should thing about splitting your application into a web frontend and a server backend. This could make many things easier.

What is the best way to create EF DbContext instance for ASP.NET MVC

In order to support lazy loading feature in EF, what is the best way to instantiate DbContext?
I know HttpContext's current item is good place to create DbContext via Application_BeginRequest method and Application_EndRequest method, but in some sample codes of MSDN and official asp.net mvc site, they just create DbContext in Controller's constructor and dispose it in controller's Dispose() method.
I think the both ways are not too different because all of those all implement session per request pattern.
I just want to make sure that my understanding is correct or not.
The Dispose() method in the controller isn't always reliable. By the same token, Session is probably not a good idea either. "Best" is probably subjective, but we've had the best success by using dependency injection (Castle Windsor) and following a Unit of Work Repository pattern.
Setup the unit of work along the following lines:
public class UnitOfWork : IUnitOfWork
{
public UnitOfWork()
{
this.Context = new MyEFEntities();
this.Context.ContextOptions.LazyLoadingEnabled = true;
}
public void Dispose()
{
this.Context.Dispose();
}
public ObjectContext Context { get; internal set; }
}
Setup your repository:
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
public Repository(IUnitOfWork unitOfWork)
{
Context = unitOfWork.Context;
ObjectSet = Context.CreateObjectSet<TEntity>();
}
public ObjectContext Context { get; set; }
public IObjectSet<TEntity> ObjectSet { get; set; }
}
Register with Castle in Global.asax:
void Application_Start()
{
this.Container.Register(
Component.For<IUnitOfWork>()
.UsingFactoryMethod(() => new UnitOfWork())
.LifeStyle
.Is(LifestyleType.PerWebRequest)
);
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(this.Container));
}
And use in your controller (or wherever you're using it, as long as it's injectable):
public class SomeController
{
public SomeController(IRepository<MyEntity> repository)
{
this.Repository = repository;
}
public IRepository<MyEntity> Repository { get; set; }
public ActionResult MyAction()
{
ViewData.Model = this.Repository.ObjectSet.Single(x => x.Condition); //or something...
}
}
Any lazy loading here could potentially be a trap for a future issue. Without DI, without a repository - its hard to see anything working without it being a hack for lazy loading. Also do you you plan on passing your entities to your view. If so this is going to create a bad overlap. The controller should package data for your view, not have things evaluated later in your view.
For MVC best practices, you should flatten out your domain model as much as possible into a viewmodel (if flattening makes sense) and use the view model. Since you would ideally then know what would be lazy loaded, it may make more sense to take the hit up front and use .Include() in your query to eager load, otherwise you can issue many many queries to the database.
I've used a session factory pattern and saved the DBContext in the session object. It will stay open per session. I haven't had problems with it so far.

EF and repository pattern - ending up with multiple DbContexts in one controller - any issues (performance, data integrity)?

Most of my knowledge of ASP.NET MVC 3 comes from reading through the book Pro ASP.NET MVC 3 Framework by Adam Freeman and Steven Senderson. For my test application I have tried to stick to their examples very closely. I am using the repository pattern plus Ninject and Moq which means that unit testing work quite well (i.e. without needing to pull data from the database).
In the book repositories are used like this:
public class EFDbTestChildRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<TestChild> TestChildren
{
get { return context.TestChildren; }
}
public void SaveTestChild(TestChild testChild)
{
if (testChild.TestChildID == 0)
{
context.TestChildren.Add(testChild);
}
else
{
context.Entry(testChild).State = EntityState.Modified;
}
context.SaveChanges();
}
}
And here is the DbContext that goes with it:
public class EFDbContext : DbContext
{
public DbSet<TestParent> TestParents { get; set; }
public DbSet<TestChild> TestChildren { get; set; }
}
Please note: to keep things simple in this extracted example I have left out the interface ITestChildRepository here which Ninject would then use.
In other sources I have seen a more general approach for the repository where one single repository is enough for the whole application. Obviously in my case I end up with quite a list of repositories in my application - basically one for each entity in my domain model. Not sure about the pros and cons about the two approaches - I just followed the book to be on the safe side.
To finally get to my question: each repository has its own DbContext - private EFDbContext context = new EFDbContext();. Do I risk ending up with multiple DbContexts within one request? And would that lead to any significant performance overhead? How about a potential for conflicts between the contexts and any consequences to the data integrity?
Here is an example where I ended up with more than one repository within a controller.
My two database tables are linked with a foreign key relationship. My domain model classes:
public class TestParent
{
public int TestParentID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public virtual ICollection<TestChild> TestChildren { get; set; }
}
public class TestChild
{
public int TestChildID { get; set; }
public int TestParentID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public virtual TestParent TestParent { get; set; }
}
The web application contains a page that allows the user to create a new TestChild. On it there is a selectbox that contains a list of available TestParents to pick from. This is what my controller looks like:
public class ChildController : Controller
{
private EFDbTestParentRepository testParentRepository = new EFDbTestParentRepository();
private EFDbTestChildRepository testChildRepository = new EFDbTestChildRepository();
public ActionResult List()
{
return View(testChildRepository.TestChildren);
}
public ViewResult Edit(int testChildID)
{
ChildViewModel cvm = new ChildViewModel();
cvm.TestChild = testChildRepository.TestChildren.First(tc => tc.TestChildID == testChildID);
cvm.TestParents = testParentRepository.TestParents;
return View(cvm);
}
public ViewResult Create()
{
ChildViewModel cvm = new ChildViewModel();
cvm.TestChild = new TestChild();
cvm.TestParents = testParentRepository.TestParents;
return View("Edit", cvm);
}
[HttpPost]
public ActionResult Edit(TestChild testChild)
{
try
{
if (ModelState.IsValid)
{
testChildRepository.SaveTestChild(testChild);
TempData["message"] = string.Format("Changes to test child have been saved: {0} (ID = {1})",
testChild.Name,
testChild.TestChildID);
return RedirectToAction("List");
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
// something wrong with the data values
return View(testChild);
}
}
It's not enough to have an EFDbTestChildRepository available but I also need an EFDbTestParentRepository. Both of them are assigned to private variables of the controller - and voila, it seems to me that two DbContexts have been created. Or is that not correct?
To avoid the issue I tried using EFDbTestChildRepository to get to the TestParents. But that obviously will only bring up those that are already hooked up to at least one TestChild - so not what I want.
Here is the code for the view model:
public class ChildViewModel
{
public TestChild TestChild { get; set; }
public IQueryable<TestParent> TestParents { get; set; }
}
Please let me know if I forgot to include some relevant code. Thanks so much for your advice!
There won't be a performance problem (unless we are talking about nanoseconds, instantiating a context is very cheap) and you won't have damaged your data integrity (before that happens you'll get exceptions).
But the approach is very limited and will work only in very simple situations. Multiple contexts will lead to problems in many scenarios. As an example: Suppose you want to create a new child for an existing parent and would try it with the following code:
var parent = parentRepo.TestParents.Single(p => p.Id == 1);
var child = new Child { TestParent = parent };
childrenRepo.SaveTestChild(child);
This simple code won't work because parent is already attached to the context inside of parentRepo but childrenRepo.SaveTestChild will try to attach it to the context inside of childrenRepo which will cause an exception because an entity must not be attached to another context. (Here is actually a workaround because you could set the FK property instead of loading the parent: child.TestParentID = 1. But without a FK property it would be a problem.)
How to solve such a problem?
One approach could be to extend the EFDbTestChildRepository by a new property:
public IQueryable<TestParent> TestParents
{
get { return context.TestParents; }
}
In the example code above you could then use only one repository and the code would work. But as you can see, the name "EFDbTest Child Repository" doesn't really fit anymore to the purpose of the new repository. It should be now "EFDbTest ParentAndChild Repository".
I would call this the Aggregate Root approach which means that you create one repository not for only one entity but for a few entities which are closely related to each other and have navigation properties between them.
An alternative solution is to inject the context into the repositories (instead of creating it in the repositories) to make sure that every repository uses the same context. (The context is often abstracted into a IUnitOfWork interface.) Example:
public class MyController : Controller
{
private readonly MyContext _context;
public MyController()
{
_context = new MyContext();
}
public ActionResult SomeAction(...)
{
var parentRepo = new EFDbTestParentRepository(_context);
var childRepo = new EFDbTestChildRepository(_context);
//...
}
protected override void Dispose(bool disposing)
{
_context.Dispose();
base.Dispose(disposing);
}
}
This gives you a single context per controller you can use in multiple repositories.
The next step might be to create a single context per request by dependency injection, like...
private readonly MyContext _context;
public MyController(MyContext context)
{
_context = context;
}
...and then configuring the IOC container to create a single context instance which gets injected into perhaps multiple controllers.
Do I risk ending up with multiple DbContexts within one request?
Yes. Each instance of a repository is going to instantiate its own DbContexts instances. Depending on the size and use of the application, this may not be a problem although it is not a very scalable approach. There are several ways of handling this though. In my web projects I add the DbContext(s) to the Request's Context.Item collection, this way it is available to all classes that require it. I use Autofac (similar to Ninject) to control what DbContexts are created within specific scenarios and how they are stored, e.g. I have a different 'session manager' for a WCF context to the one for a Http context.
And would that lead to any significant performance overhead?
Yes, but again not massively if the application is relatively small. As it grows though, you may notice the overhead.
How about a potential for conflicts between the contexts and any
consequences to the data integrity?
One of the reasons for using an ORM like this is so that changes can be maintained within the DbContext. If you are instantiating multiple context instances per request you lose this benefit. You wouldn't notice conflicts or any impact of the integrity per se unless you were handling a lot of updates asynchronously.
As promised I post my solution.
I came across your question because I was having trouble with the IIS application pool memory growing beyond limits and having multiple DBContexts was one of my suspects. In retrospect it is fair to say that there were other causes for my trouble. However, it challenged me to find a better layer based design for my repository.
I found this excellent blog: Correct use of Repository and Unit Of Work patterns in ASP.NET MVC leading me to the right direction. The redesign is based on the UnitOfWork pattern. It enables me to have just one constructor parameter for all my controllers instead of "never ending constructor parameters". And after that, I was able to introduce proactive caching as well, which solved a great deal of the earlier mentioned trouble I was having.
Now I only have these classes:
IUnitOfWork
EFUnitOfWork
IGenericRepository
EFGenericRepository
See the referred blog for complete information and implementation of these classes. Just to give an example, IUnitOfWork contains repository definitions for all entities that I need, like:
namespace MyWebApp.Domain.Abstract
{
public interface IUnitOfWork : IDisposable
{
IGenericRepository<AAAAA> AAAAARepository { get; }
IGenericRepository<BBBBB> BBBBBRepository { get; }
IGenericRepository<CCCCC> CCCCCRepository { get; }
IGenericRepository<DDDDD> DDDDDRepository { get; }
// etc.
string Commit();
}
}
The Dependency Injection (DI) is just one statement (I use Ninject):
ninjectKernel.Bind<IUnitOfWork>().To<EFUnitOfWork>();
The Controllers-constructors are maintainable:
public class MyController : BaseController
{
private MyModel mdl = new MyModel();
private IUnitOfWork _context;
public MyController(IUnitOfWork unitOfWork)
{
_context = unitOfWork;
// intialize whatever needs to be exposed to the View:
mdl.whatever = unitOfWork.SomeRepository.AsQueryable();
}
// etc.
Within the Controller I can use _context to access all repositories, if needed. The nice part of it, is that it needs just a single Commit()-call to save changed data for all repositories:
_context.Commit();

Resources