Unity and Unitofwork

Asked

Viewed 131 times

1

Salve galera,

I created a small project to apply Ioc using the Unity MS. First I always used the concept of Unitofwork just instantiated it into my controllers, But now I want to inject them. When I start the web application it correctly lists the database information, but whenever I call the Savechanges is making the mistake: {"The Operation cannot be completed because the Dbcontext has been disposed."}

I can’t find the reason for this, since the context is being injected into Unitofwork correctly, otherwise he wouldn’t even be able to list the bank’s information. Follows my code.

Unity Config

using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Mvc;
using MyMoney.DAL.Repositories;
using MyMoney.DAL.UnitOfWork;
using MyMoney.Domain.Interfaces.Repositories;
using System.Web.Mvc;

namespace MyMoney.DAL.Unity
{
    public class Bootstrapper
    {
        public static IUnityContainer Initialise()
        {
            var container = BuildUnityContainer();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
            return container;
        }
        private static IUnityContainer BuildUnityContainer()
        {
            var container = new UnityContainer();

            container.RegisterType(typeof(ITransaction), typeof(TransactionRepository));

            container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new ContainerControlledLifetimeManager());

            return container;
        }
    }
}

Unitofwork

using System;
using MyMoney.DAL.Context;
using MyMoney.Domain.Interfaces.Repositories;

namespace MyMoney.DAL.UnitOfWork
{
    public class UnitOfWork : IUnitOfWork
    {
        private MyMoneyContext _context;
        private ITransaction _transactionRepository;

        public UnitOfWork(MyMoneyContext context, ITransaction transactionRepository)
        {
            this._context = context;
            this._transactionRepository = transactionRepository;
        }

        public ITransaction TransactionRepository
        {
            get
            {
                return _transactionRepository;
            }
        }

        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);
        }
    }
}

Repository base

using MyMoney.DAL.Context;
using MyMoney.Domain.Interfaces.Repositories;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace MyMoney.DAL.Repositories
{
    public abstract class RepositoryBase<TEntity> : IDisposable, IRepositoryBase<TEntity> where TEntity : class
    {
        protected MyMoneyContext db;

        public RepositoryBase(MyMoneyContext db)
        {
            this.db = db;
        }

        public virtual void Add(TEntity obj, Guid userId)
        {
            db.Set<TEntity>().Add(obj);
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    db.Dispose();
                }
            }

            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public virtual IEnumerable<TEntity> GetAll(Guid userId)
        {
            return db.Set<TEntity>().ToList();
        }

        public virtual TEntity GetById(int id, Guid userId)
        {
            return db.Set<TEntity>().Find(id);
        }

        public virtual void Remove(int id)
        {
            TEntity obj = db.Set<TEntity>().Find(id);
            db.Set<TEntity>().Remove(obj);
        }

        public void Save()
        {
            db.SaveChanges();
        }

        public virtual void Update(TEntity obj)
        {
            db.Entry(obj).State = EntityState.Modified;
        }
    }
}

Repository

using MyMoney.DAL.Context;
using MyMoney.Domain.Entities;
using MyMoney.Domain.Interfaces.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MyMoney.DAL.Repositories
{
    public class TransactionRepository : RepositoryBase<Transaction>, ITransaction
    {
        public TransactionRepository(MyMoneyContext db) : base(db)
        {
        }

        public override IEnumerable<Transaction> GetAll(Guid userId)
        {
            return db.Transations.Where(x => x.UserId == userId).ToList();
        }

        public override void Add(Transaction transaction, Guid userId)
        {
            transaction.UserId = userId;
            db.Transations.Add(transaction);
        }

        public override Transaction GetById(int id, Guid userId)
        {
            return db.Transations.Where(x => x.UserId == userId && x.Id == id).FirstOrDefault();
        }
    }
}

Controller

using AutoMapper;
using MyMoney.Domain.Entities;
using MyMoney.MVC.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using System.Data.Entity.Validation;
using System.Text;
using MyMoney.DAL.UnitOfWork;

namespace MyMoney.MVC.Controllers
{
    public class TransactionsController : Controller
    {
        readonly IUnitOfWork _unitOfWork;
        readonly Guid userId;

        public TransactionsController(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
            userId = new Guid(System.Web.HttpContext.Current.User.Identity.GetUserId());
        }

        // GET: Transactions
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult TransactionList()
        {
            var tList = Mapper.Map<IEnumerable<Transaction>, IEnumerable<TransactionViewModel>>(_unitOfWork.TransactionRepository.GetAll(userId));

            return this.PartialView("TransactionList", tList.ToList());
        }

        public PartialViewResult EditCreateForm(int id = 0)
        {
            TransactionViewModel viewModel = null;

            if (id > 0)
            {
                var transaction = _unitOfWork.TransactionRepository.GetById(id, userId);
                viewModel = Mapper.Map<Transaction, TransactionViewModel>(transaction);
            }

            return this.PartialView("EditCreate", viewModel);
        }

        [HttpPost]
        public ActionResult EditCreate(TransactionViewModel viewModel)
        {
            try
            {
                if (viewModel.Id > 0)
                {
                    var transactionDomain = Mapper.Map<TransactionViewModel, Transaction>(viewModel);
                    _unitOfWork.TransactionRepository.Update(transactionDomain);
                    _unitOfWork.Save();

                    return Json(0);
                }
                else
                {
                    var transactionDomain = Mapper.Map<TransactionViewModel, Transaction>(viewModel);
                    _unitOfWork.TransactionRepository.Add(transactionDomain, userId);
                    _unitOfWork.Save();

                    return Json(0);
                }
            }
            catch (Exception ex)
            {
                var msg = new StringBuilder();

                if (ex is DbEntityValidationException)
                {
                    var errors = ex as DbEntityValidationException;
                    foreach (var err in errors.EntityValidationErrors.SelectMany(x => x.ValidationErrors.Select(get => get.ErrorMessage)))
                    {
                        msg.AppendLine(err);
                    }
                }
                else
                {
                    msg.AppendLine(ex.Message);
                }

                return Json(msg.ToString());
            }
        }

        [HttpPost]
        public ActionResult DeleteConfirmed(int id)
        {
            try
            {
                _unitOfWork.TransactionRepository.Remove(id);
                _unitOfWork.Save();

                return Json(0);
            }
            catch (Exception ex)
            {
                var msg = new StringBuilder();

                if (ex is DbEntityValidationException)
                {
                    var errors = ex as DbEntityValidationException;
                    foreach (var err in errors.EntityValidationErrors.SelectMany(x => x.ValidationErrors.Select(get => get.ErrorMessage)))
                    {
                        msg.AppendLine(err);
                    }
                }
                else
                {
                    msg.AppendLine(ex.Message);
                }

                return Json(msg.ToString());
            }
        }

        protected override void Dispose(bool disposing)
        {
            _unitOfWork.Dispose();
            base.Dispose(disposing);
        }
    }
}

Context

using MyMoney.DAL.EntityCfg;
using MyMoney.Domain.Entities;
using System;
using System.Data.Entity;
using System.Linq;

namespace MyMoney.DAL.Context
{
    public class MyMoneyContext : DbContext
    {
        public MyMoneyContext()
            : base("MyMoney")
        {

        }

        public DbSet<Transaction> Transations { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new TransactionConfig());
        }

        public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries().Select(x => x))
            {
                if (entry.State == EntityState.Added)
                {
                    entry.Property("Date").CurrentValue = DateTime.Now;
                }

                if (entry.State == EntityState.Modified)
                {
                    entry.Property("Date").IsModified = false;
                    entry.Property("UserId").IsModified = false;
                }
            }

            return base.SaveChanges();
        }
    }
}

If you need more information, I’ll put it here. Thanks for your help from now on.

New Information:

I figured out why disposed. The context I use when I call Savechanges, in the controller is _unitOfWork.Save(), is a different instance of the context that is in the repository. That is, in Unitofwork One instance of the context is injected and another instance of the context is injected into the repository. The solution may be to call the Savechanges in the context of the repository, but in my opinion this is wrong, this should be within the Unitofwork same. Another solution is to inject the Unitiofwork within the repository and thus use the context of Unitofwork, only that in the design that is would look like this:

Unitofwork

public UnitOfWork(MyMoneyContext context, ITransaction transactionRepository)
{
   this._context = context;
   this._transactionRepository = transactionRepository;
}

public MyMoneyContext DbContext
{
   get
   {
      return _context;
   }
}

Repositorybase

protected MyMoneyContext db;

public RepositoryBase(IUnitOfWork db)
{
   this.db = db.DbContext;
}

Transactionrepository

public TransactionRepository(IUnitOfWork db) : base(db)
{
}

The problem is that I create a circular depenica that will cause a stackoverflow. Does anyone have a better idea of how to solve?

  • I think it would be a good idea to show the RepositoryBase

  • @Brunocosta, added Repositorybase.

  • This Unitofwork is a freak. Get rid of it: http://answall.com/questions/51536/quando-usar-entity-framework-com-repository-pattern/80696#80696

  • @Ciganomorrisonmendez, thanks for the link, the information is very interesting, something that should be reflected! But in my case I really want to create more layers of abstraction, so it doesn’t serve as an answer to my question.

  • It’s not an "answer to your question," it’s a recommendation. There is an insistence on using this, which is an anti-standard, encouraged by some, but it is totally incorrect. Also, your answer does not answer the question in the error you have.

  • What I want most is a better answer than I found. :)

Show 1 more comment

1 answer

-1


The best solution for my case was this:

Unitofwork

public class UnitOfWork : IUnitOfWork
    {
        private MyMoneyContext context = new MyMoneyContext();
        private TransactionRepository transactionRepository;

        public TransactionRepository TransactionRepository
        {
            get
            {
                if (transactionRepository == null)
                {
                    transactionRepository = new TransactionRepository(context);
                }

                return transactionRepository;
            }
        }

        public void Save()
        {
            context.SaveChanges();
        }
    }

I urge the context in Unitofwork and create a method that instantiates the repository passing the instance of the context, that is, I inject nothing else in the Unitofwork. Logically I also changed the constructs of the repositories to receive the context and not Unitofwork and continue using the Savechanges in it as I wanted. Everything working here. :)

Browser other questions tagged

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