Entity Framework 5 with Repositories retrieving old data - c#

I have a problem with EF5. I am using MVC 4.5
I am trying to make the 1 context per request "pattern".
I am not using "unit of work" pattern, nor testing or DI.
I am using the Generic Repository pattern to interact with DB. Each repository uses the same context mantained by a singleton "DataContextManager".
In each request in the global asax I refresh the context, but something wrong is happening: ie: I have a paged list and moving by the pages if i change data in DB manualy it doesnt refresh correctly. It's not an HTML cache issue, i tested it.
I know is a EF Context problem because i have "something like this":
private static Context C; //for the singleton. And in global.asax
public Application_BeginRequest()
{
DataContextManager.RefreshNew();
}
protected void Application_EndRequest(object sender, EventArgs e)
{
Domain.DataContextManager.Dispose();
}
And the first time the list works and in the second page i get an error saying that the
Context is disposed.
I read something of using the context in Static variables, but i don't know whats happening. I would like to use something simple like this, because to implement the UnitOfWork pattern i will need to change a lot of code.
Here is a little snnipet of my classes:
public class DataContextManager
{
private static Entities _Context;
private const string ConnectionString = "connString";
public static Entities Context
{
get
{
if (DataContextManager._Context == null)
DataContextManager._Context = new Entities(ConfigurationManager.ConnectionStrings[ConnectionString].ConnectionString);
return DataContextManager._Context;
}
}
//This method is not necessary but made it for testing
public static void RefreshNew()
{
DataContextManager._Context = new Entities(ConfigurationManager.ConnectionStrings[ConnectionString].ConnectionString);
}
public static void Dispose()
{
if (DataContextManager._Context != null)
{
DataContextManager._Context.Dispose();
DataContextManager._Context = null;
}
}
}
And repositories use DataContextManager like this:
public class BaseRepository<TEntity> where TEntity : class
{
internal Entities context;
internal DbSet<TEntity> dbSet;
public BaseRepository()
: this(DataContextManager.Context)
{
}
public BaseRepository(Entities context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
Thanks in advance!
Pablo.

I don't know that you really need the manager class, since everything seems to just access the DbContext property.
That being said, you should normally avoid using DbContext in a static class; I don't have any canonical source to back that up, but my personal experience has been that it at some point causes more problems than any benefit having a static class provides. So, I'd update the manager like so:
public class DataContextManager
{
private readonly string connectionToUse = string.Empty;
private Entities _context;
public Entities Context
{
get
{
if (_context == null)
{
_context = new Entities(WebConfigurationManager.ConnectionStrings[connectionToUse].ConnectionString);
}
return _context;
}
}
public DataContextManager()
{
connectionToUse = "connString";
}
public DataContextManager(string key)
{
connectionToUse = key;
}
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposeAll)
{
if (disposeAll)
{
_context.Dispose();
}
_context = null;
}
#endregion
}
Then you simply add a protected field to each of your controllers and instantiate the manager in the controller's constructor:
protected DataContextManager Manager = null;
public HomeController()
{
Manager = new DataContextManager();
// or
//
//__manager = new DataContextManager("connection-To-Use");
}
If all of your controllers use the same DbContext class, you could create a BaseController class that inherits System.Web.Mvc.Controller and move the manager into it, which saves some duplication.

Related

How to change between databases with the same schema but different names using EF and dependency injection?

I have a Web API web service that uses EF for database operations and Unity for dependency injection. I have multiple databases with different names but the same schema. There's one database per retail store. When the user logs in, depending on his privileges, he can select which store he wants to work with. This is a challenge using dependency injection because I have to change the database after a repository has been injected. I have something that works but am not sure if it's the best approach.
My specific questions are:
Is this a good approach for this problem? I've seen other questions that mention changing the connection string at run time, but I think I'd either have to have a connection string per store in my Web.Config or build the connection string dynamically somehow.
Do I need the Dispose logic in my factory? If I were injecting a repository directly I know I wouldn't need it. Since I'm generating the repo from an injected factory, can I trust Unity to dispose of the repo and close the db connections at some point? Should I use using statements around the generated repos instead?
Some questions I looked at while trying to solve this problem are this one, this one, and this one. However, none of them directly accomplish what I'm trying to do. Below is my current solution.
This is my repository and its interface. I've left out some of the methods for brevity:
IGenericRepository
public interface IGenericRepository<T> where T: class
{
IQueryable<T> Get();
void ChangeDatabase(string database);
void Update(T entityToUpdate);
void Save();
}
GenericRepository
public class GenericRepository<TDbSet, TDbContext> :
IGenericRepository<TDbSet> where TDbSet : class
where TDbContext : DbContext, new()
{
internal DbContext Context;
internal DbSet<TDbSet> DbSet;
public GenericRepository() : this(new TDbContext())
{
}
public GenericRepository(TDbContext context)
{
Context = context;
DbSet = Context.Set<TDbSet>();
}
public virtual IQueryable<TDbSet> Get()
{
return DbSet;
}
public void ChangeDatabase(string database)
{
var dbConnection = Context.Database.Connection;
if (database == null || dbConnection.Database == database)
return;
if (dbConnection.State == ConnectionState.Closed)
{
dbConnection.Open();
}
Context.Database.Connection.ChangeDatabase(database);
}
public virtual void Update(TDbSet entityToUpdate)
{
DbSet.Attach(entityToUpdate);
Context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void Save()
{
Context.SaveChanges();
}
}
In order to use dependency injection I'm injecting a repository factory to which I can pass a database name. The factory creates a repository with the connection string's default database, changes the database to the one specified, and returns the repository.
IRepositoryFactory
public interface IRepositoryFactory
{
IGenericRepository<TDbSet> GetRepository<TDbSet>(string dbName) where TDbSet : class;
}
StoreEntitiesFactory
public class StoreEntitiesFactory : IRepositoryFactory
{
private bool _disposed;
readonly StoreEntities _context;
public StoreEntitiesFactory()
{
_context = new StoreEntities();
}
public IGenericRepository<TDbSet> GetRepository<TDbSet>(string dbName) where TDbSet : class
{
var repo = new GenericRepository<TDbSet, StoreEntities>(_context);
repo.ChangeDatabase(dbName);
return repo;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_context.Dispose();
}
_disposed = true;
}
~StoreEntitiesFactory()
{
Dispose(false);
}
}
This is how I inject the repository factory in my WebApiConfig file:
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = new UnityContainer();
container.RegisterType<IRepositoryFactory, StoreEntitiesFactory>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
}
}
Finally, this is how I would use the factory in my controller:
StoreController
public class StoreController : ApiController
{
private readonly IRepositoryFactory _storeEntitiesRepoFactory;
public StoreController(IRepositoryFactory storeEntitiesRepoFactory)
{
_storeEntitiesRepoFactory = storeEntitiesRepoFactory;
}
[HttpGet]
public IHttpActionResult Get()
{
var dbName = getStoreDbName(storeNumberWeGotFromSomewhere);
try
{
var employeeRepo = _storeEntitiesRepoFactory.GetRepository<Employee>(dbName);
var inventoryRepo = _storeEntitiesRepoFactory.GetRepository<Inventory>(dbName);
var employees = employeeRepo.Get().ToList();
var inventory = inventoryRepo.Get().ToList();
}
catch (Exception ex)
{
return InternalServerError();
}
}
}
I think you probably want your IRepositoryFactory implementations to return the same repository for the same dbName. As it is written now, calling StoreEntitesFactory.GetRepository with two different dbName parameters will cause problems since it gives the same instance of StoreEntites to every repository.
To illustrate...
public class DemonstrationController
{
private readonly IRepositoryFactory _storeEntitiesRepoFactory;
public DemonstrationController(IRepositoryFactory storeEntitiesRepoFactory)
{
_storeEntitiesRepoFactory = storeEntitiesRepoFactory;
}
[HttpGet]
public IHttpActionResult Get()
{
var empRepo1 = _storeEntitiesRepoFactory.GetRepository("DB1");
var empRepo2 = _storeEntitiesRepoFactory.GetRepository("DB2");
// After the second line, empRepo1 is connected to "DB2" since both repositories are referencing the same
// instance of StoreEntities
}
}
If you changed StoreEntitiesFactory to return the same repository based on the given parameter, this would solve that problem.
public class StoreEntitiesFactory : IRepositoryFactory
{
private bool _disposed;
private Dictionary<string, StoreEntities> _contextLookup;
public StoreEntitiesFactory()
{
_contextLookup = new Dictionary<string, StoreEntities>();
}
public IGenericRepository<TDbSet> GetRepository<TDbSet>(string dbName) where TDbSet : class
{
if (!_contextLookup.TryGetValue(dbName, out StoreEntities context))
{
context = new StoreEntities();
// You would set up the database here instead of in the Repository, and you could eliminate
// the ChangeDatabase function.
_contextLookup.Add(dbName, context);
}
return new GenericRepository<TDbSet, StoreEntities>(context);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize();
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
foreach (var context in _contextLookup.Values)
{
context.Dispose();
}
}
_disposed = true;
}
}
}
As for the second question, you would need the dispose logic in the factory since it owns the instances of StoreEntities being created. No need to use using statements around the repositories it creates, just let Unity dispose of the factory.
I'd recommend you to use a design pattern called a Strategy Pattern to solve this problem.
This pattern allows you to change between two or more strategies on runtime.
Reference: https://en.wikipedia.org/wiki/Strategy_pattern
For the injection, I'd suggest you register two concrete classes on the Unity, one for each DB Connection and call the Resolve method for the one you need passing the string to instantiate the DB.
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();
container.RegisterType<ICar, Audi>("LuxuryCar");
ICar bmw = container.Resolve<ICar>(); // returns the BMW object
ICar audi = container.Resolve<ICar>("LuxuryCar"); // returns the Audi object
Reference: https://www.tutorialsteacher.com/ioc/register-and-resolve-in-unity-container
About the Dispose, you can config all of these concrete classes to the DBs as Singletons, and let all the connections opened, but you will need to verify if this is possible to your application.

Creating a simple unit of work with Entity Framework and no repository

I've been trying to implement a .net MVC Unit of Work API (rather than creating a separate repository), but it doesn't feel right. Am I going about this the correct way?
BaseController
public class BaseController : ApiController
{
protected DBEntities _dbEntities;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_dbEntities = new DBEntities();
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
_dbEntities.SaveChanges();
}
}
MyController
public class MyController : BaseController
{
public HttpResponseMessage PutMyObject(int id, int id2)
{
if (id != 0)
{
var myObject = _dbEntities.MyObjects.Where(x => x.id == id);
if (myObject.Count() > 0)
{
MyObject temp = myObject.SingleOrDefault();
temp.Processed = true;
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound);
}
}
else
{
/* do some other stuff */
}
}
}
My thinking around this is that the controller action is a single Unit of Work. The database connection is opened when the controller action starts, and SaveChanges is called once the response is returned.
Am I going about this in the correct manner? do i need to dispose of _dbentities after savechanges is called within the BaseController? (or is this a better question for code review exchange)
I think, It would be a bad design for OOP architecture and flexibility. Because, you have to provide database actions in your main MVC project and you couldn't provide them in other layers. So, you should provide repository pattern and you should access the repositories from main MVC project and other required projects. So, I suggest you to handle _dbEntities object in a singleton class for per thread.
Sample singleton class would be like this;
public class UnitOfWorkSampleContextBase : IDisposable
{
[ThreadStatic]
private static UnitOfWorkSampleContextBase _instance;
public static UnitOfWorkSampleContextBase Instance
{
get
{
if (_instance == null)
{
_instance = new UnitOfWorkSampleContextBase();
}
return _instance;
}
}
public SampleDbContext Context { get; private set; }
private UnitOfWorkSampleContextBase()
{
}
public void Commit()
{
Context.SaveChanges();
}
public void ResolveContext()
{
Context = new SampleDbContext(ConfigurationManager.ConnectionStrings["MainDatabase"].ConnectionString);
}
public void Dispose()
{
Context.Dispose();
Context = null;
}
}
And you can create the DbContext like this;
UnitOfWorkSampleContextBase.Instance.ResolveContext();
Then, you can perform actions in context like this;
var context = UnitOfWorkSampleContextBase.Instance.Context;
var records = context.sampleEntities.ToList();
Finally, you can commit and dispose the context like this;
UnitOfWorkSampleContextBase.Instance.Commit();
UnitOfWorkSampleContextBase.Instance.Dispose();
The singleton class should be in repository or base layer to be accessed desired repository classes.
Note : If you are using CastleWindsor or something like that, creating
and commiting the context would be better in an interceptor. Also, it is very important that the singleton context class should be initialized for per thread.

Ninject, MVC5, EF6, Repository + UoW

I'm having two problems, the first is scaling and became visible while load testing.
Under load, things quickly (10 concurrent or less) fail with the error:
There is already an open DataReader associated with this Command which must be closed first.
Or
ExecuteReader requires an open and available Connection. The connection's current state is open.
The stack trace references a repository every time, example:
Line 23: public AboutViewDto GetAboutView()
Line 24: {
Line 25: var featured = UnitOfWork.FaqRepository
Line 26: .GetFeatured()
Original NinjectDependencyResolver:
public class NinjectDependencyResolver
: IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver() : this(new StandardKernel())
{
}
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
AddBindings(_kernel);
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType);
}
public void Dispose()
{
// nothing??
}
private static void AddBindings(IBindingRoot kernel)
{
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InSingletonScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InSingletonScope();
kernel.Bind<IFaqRepository>().To<FaqRepository>().InSingletonScope();
kernel.Bind<IListValueRepository>().To<ListValueRepository>().InSingletonScope();
kernel.Bind<INoticeRepository>().To<NoticeRepository>().InSingletonScope();
kernel.Bind<IOrganizationRepository>().To<OrganizationRepository>().InSingletonScope();
kernel.Bind<ITagRepository>().To<TagRepository>().InSingletonScope();
kernel.Bind<IAdminService>().To<AdminService>();
kernel.Bind<IAutoMapperService>().To<AutoMapperService>();
kernel.Bind<IHomeService>().To<HomeService>();
kernel.Bind<IInfoService>().To<InfoService>();
kernel.Bind<IMailService>().To<MailService>();
kernel.Bind<INoticeService>().To<NoticeService>();
kernel.Bind<IOrganizationService>().To<OrganizationService>();
kernel.Bind<ISearchService>().To<SearchService>();
kernel.Bind<IValidator<QuestionDto>>().To<QuestionDtoValidator>();
kernel.Bind<IValidator<NoticeCommentDto>>().To<CommentDtoValidator>();
kernel.Bind<IValidator<NoticeContactDto>>().To<NoticeContactDtoValidator>();
kernel.Bind<IValidator<NoticeDto>>().To<NoticeDtoValidator>();
kernel.Bind<IValidator<OrganizationDto>>().To<OrganizationDtoValidator>();
}
}
}
I had a hunch that InSingletonScope() was causing the problem so I changed it to:
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
And changed all of the other SingletonScopes to RequestScope.
After making that change, the site handles 400+ concurrent users without any failures, however...
Now no commits work against the database. I can trace the calls through the controller, to the service, to the repository, and to the DBContext commit, but the inserts or updates are not happening.
I'll post snippets of each item here in hopes someone can spot the dumb error we've made or suggest improvements.
Snippets follow:
Activity, update a Notice, everything involved:
1) Ninject:
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
kernel.Bind<INoticeService>().To<NoticeService>();
.. etc...
2) Controller:
public sealed class NoticeController : BaseController
{
public NoticeController(IAutoMapperService autoMapperService, INoticeService noticeService)
{
AutoMapperService = autoMapperService;
NoticeService = noticeService;
}
...
3) NoticeService
public class NoticeService : BaseService, INoticeService
{
public NoticeService(
IUnitOfWork unitOfWork,
IAutoMapperService autoMapperService,
IValidator<NoticeDto> noticeDtoValidator)
: base(unitOfWork)
{
AutoMapperService = autoMapperService;
NoticeDtoValidator = noticeDtoValidator;
}
4) Unit of Work
public class UnitOfWork : IUnitOfWork
{
private IDataContext _dataContext;
private bool _disposed;
private ObjectContext _objectContext;
private DbTransaction _transaction;
public UnitOfWork(
IDataContext dataContext,
INoticeRepository noticeRepository)
{
_dataContext = dataContext;
NoticeRepository = noticeRepository;
}
5) Notice Repository
public class NoticeRepository : Repository<Notice>, INoticeRepository
{
public NoticeRepository(IDataContext context) : base(context)
{
}
...
6) Controller Action
public ActionResult Create(NoticeViewModel notice)
{
notice.TypeId = Convert.ToInt32(NoticeType.ManuallyEnteredDocument);
var newNotice = AutoMapperService.Map<NoticeViewModel, NoticeDto>(notice);
NoticeService.Create(newNotice);
return RedirectToAction("Details", new { name = notice.Arc });
}
7) NoticeService.Create(new):
public void Create(NoticeDto notice)
{
NoticeDtoValidator.ValidateAndThrow(notice);
var newNotice = AutoMapperService.Map<NoticeDto, Notice>(notice);
UnitOfWork.NoticeRepository.Add(newNotice);
UnitOfWork.SaveChanges();
}
8) Generic Repository Add():
public virtual void Add(TEntity entity)
{
entity.ObjectState = ObjectState.Added;
_dbSet.Attach(entity);
_context.SyncObjectState(entity);
}
9) UnitOfWork SaveChanges():
public int SaveChanges()
{
return _dataContext.SaveChanges();
}
When I step through this, the entity that is attached in #8 looks right, the status is added, when save changes is called there are no changes recorded in the base SaveChanges():
public override int SaveChanges()
{
SyncObjectsStatePreCommit();
base.ChangeTracker.DetectChanges();
var result = base.ChangeTracker.HasChanges();
var changes = base.SaveChanges();
result here is false
How could that be? What am I missing, other than abstraction hell and UoW/Repos on top of EF6 context, (I inherited this).
Someone out there see anything ELSE dumb?
No errors, no exceptions, the inserts just don't happen.
Problem solved, the issue was that Ninject was injecting a different context into our repositories.
We found two ways to solve this:
Option 1) In our unit of work we created an additional constructor that just receives a dbcontext and creates new repositories passing them the dbcontext. We left the old constructor as well so we can inject the repos for testing. This worked great and was a trivial change to make.
Option 2) Removed Ninject and overloaded the constructors for each Controller, manually creating the items. Since this project was small, we only had to touch 6 controllers and it worked fine, just 4 new lines of code in each. We left the old constructor as well so we can inject the services for testing.

How do implement Unit of Work, Repository and Business Logic in ASP MVC?

I currently been assigned to a asp mvc project using entity framework. This will be a Line of Business application. I want to develop this app using repository and unit of work pattern. I'm new to this pattern (and new to .net too) and i am having a problem in understanding the pattern and how to implement it.
I have read numerous articles and i think this is how my application should be
Entity Framework -> Repository -> Unit of Work -> Client (Asp MVC)
I attach some code from this article
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
using System;
using ContosoUniversity.Models;
namespace ContosoUniversity.DAL
{
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;
}
}
public GenericRepository<Course> CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new GenericRepository<Course>(context);
}
return courseRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
Unit of Work will have repositories and will create DBContext upon creation
So controller will create Unit of Work upon creation.
To Show data i will use this code
var department = UoW.departmentRepository.Find(1);
return View(department);
and when client click save button, i will run this code
UoW.departmentRepository.Update(department);
UoW.Save();
My question:
What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.
Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?
Is there a complete sample project for this kind of application?
EDIT
As Ant P adviced, i need to add another layer to put my business logic.
This is what i have come so far
Unit Of Work:
public class UnitOfWork : IDisposable
{
private DBContext _context = new DBContext();
public DBContext Context
{
get
{
return this._context;
}
}
public void Save()
{
_context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Business Logic:
public class SalesBusinessLogic : IDisposable
{
private ICustomerRepository _customerRepo;
private ISalesRepository _salesRepo;
private UnitOfWork _uow;
public SalesBusinessLogic(UnitOfWork uow)
{
this._uow = uow;
}
public ICustomerRepository CustomerRepo
{
get
{
if (this._customerRepo == null)
{
this._customerRepo = new CustomerRepository(this._uow);
}
return this._customerRepo;
}
}
public ISalesRepository SalesRepo
{
get
{
if (this._salesRepo == null)
{
this._salesRepo = new SalesRepository(this._uow);
}
return this._salesRepo;
}
}
public bool Validate(Sales sales)
{
//this is where validation performed
return true;
}
}
Controller:
public SalesController : Controller
{
private UnitOfWork _uow = new UnitOfWork();
private SalesBusinessLogic _bl = new SalesBusinessLogic(this._uow);
public ActionResult Index()
{
var sales = _bl.SalesRepo.Find(1);
sales.CustomerID = 1;
if _bl.Validate(sales)
{
_bl.SalesRepo.Update(sales);
_uow.Save();
}
return View(sales);
}
}
Here UnitOfWork act only as provider of dbcontext, which will be consumed by business logic and repository.
Repository will be in BusinessLogic class.
Server side validation will be handled by BusinessLogic and client side validation will be handled by viewmodel in Web Layer.
My only concern is that dbcontext in UnitofWork is publicly accessible.
Am i in the right direction here?
What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.
This isn't an issue - the controller is instantiated per request. It doesn't persist while the user views the page. It sounds like you're misunderstanding at what point the controller is instantiated. When you instantiate the UnitOfWork within the controller's constructor, the process flow goes like this:
The user issues a POST request (by clicking 'Save').
The request reaches the server and the controller is instantiated (thereby instantiating the unit of work).
The action method is called.
The unit of work is disposed.
Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?
Typically, your business logic would be abstracted into a separate layer that sits between your web application and your repositories. Tutorials that show you repositories injected directly into controllers assume that you have "thin" business logic.
However, validation definitely isn't the job of a repository. You should create a separate view model for each view and validate those in your controller. The repository should be used pretty much solely for CRUD operations.

Trouble getting Unit of Work and Repository Pattern Working in MVC app

I have a View that is bound to a NewUserViewModel which is posted to this method of the controller.
[HttpPost]
public ActionResult NewUser(NewUserViewModel newUser)
{
var user = new User();
user.Id = newUser.Id;
user.Email = newUser.Email;
//more mapping hidden for brevity
//here is where the trouble starts
_userService.AddNewUser(user);
return RedirectToAction("Users");
}
The _userService is in a private field that is instantiated in the controllers constructor like this
private IUserService _userService;
public ControllerName()
{
_userService = new UserService();
}
The AddNewUser method on the _userService looks like this.
public void AddNewUser(User newUser)
{
using (var uow = new UnitOfWorkUser(new Context()))
{
using (var _userRepo = new UserRepository(uow))
{
_userRepo.InsertOrUpdate(newUser);
uow.Save();
}
}
}
The constructor of the UserRepository looks like this.
private Context _context;
public UserRepository(UnitOfWorkUser unitOfWork)
{
_context = unitOfWork.Context;
}
and the unitOfWorkLooks like this.
public class UnitOfWorkUser :IDisposable, IUnitOfWork
{
private readonly Context _context;
public UnitOfWorkUser(Context context = null)
{
_context = context ?? new Context();
}
public int Save()
{
return _context.SaveChanges();
}
internal Context Context
{
get { return _context; }
}
public void Dispose()
{
_context.Dispose();
}
}
And the InsertOrUpdate Method on the _userRepo looks like this.
public virtual void InsertOrUpdate(User user)
{
if (user.Id == default(int))
{
_context.Users.Add(user);
}
else
{
_context.Entry(user).State = System.Data.EntityState.Modified;
}
}
When I get to the
_context.Users.Add(user);
in the method above I get this error
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I thought by passing in the Context with the UnitOfWork Object in the constructor of the UserRepository I was going to be avoiding these errors.
What am I doing wrong?
There is a better approach to use UOW in asp.net mvc, you dont consider many aspects of entity life time in context, so I suggest reading this article
This looks very wrong to me. The purpose of unit work pattern is to consolidate all your "work" in one object. There is several issue with the following code:
Looks like you are disposing the DBContext Twice
Since you only need dbcontext, you shouldn't only pass dbcontext to the repository instead of UOW object
You might want to have a internal reference to the UserRepository. It should be used to group your Repositories and ensure they all share the same EF context instance. A sample will look like UnitOfWorkUser.UserRepo.Save(newUser)
using (var uow = new UnitOfWorkUser(new Context()))
{
using (var _userRepo = new UserRepository(uow))
{
_userRepo.InsertOrUpdate(newUser);
uow.Save();
}
}
Here is an example on how you use UOW,
http://www.mattdurrant.com/ef-code-first-with-the-repository-and-unit-of-work-patterns/

Categories