Jive Boogie
Jive Boogie

Reputation: 1265

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?

Upvotes: 1

Views: 1033

Answers (2)

Jack
Jack

Reputation: 2660

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:

  1. Looks like you are disposing the DBContext Twice

  2. Since you only need dbcontext, you shouldn't only pass dbcontext to the repository instead of UOW object

  3. 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/

Upvotes: 0

Babak Fakhriloo
Babak Fakhriloo

Reputation: 2126

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

Upvotes: 0

Related Questions