19

I'm writing a simple blog application and trying to establish CRUD operations in my generic repository pattern but I'm getting an error on my update method that says:

'System.Data.Entity.DbSet' does not contain a definition for 'Entry' and no extension method 'Entry' accepting a first argument of type 'System.Data.Entity.DbSet' could be found (are you missing a using directive or an assembly reference?)

I followed a post that explained how to 'fake' Entry() by adding additional level of indirection over DbContext. However in MVC 5 we're inheriting from: IdentityDbContext and not DbContext. I did try implementing the authors fix but the error persists.

My Question

How can I add an update method to my repository in Entity Framework 6 using IdentityDbContext? If we aren't supposed to do it this way then how do I update a record with this pattern?

I should note that all other the other methods work as expected.

My generic Repository:

public class BlogEngineRepository<T> : IRepository<T> where T : class
    {
        protected DbSet<T> DbSet;

        public BlogEngineRepository(DbContext dataContext)
        {
            DbSet = dataContext.Set<T>();
        }

        #region IRepository<T> Members

        public void Insert(T entity)
        {
            DbSet.Add(entity);
        }

        public void Delete(T entity)
        {
            DbSet.Remove(entity);
        }

        public void Update(T entity)
        { 

           DbSet.Entry(entity).State = System.Data.Entity.EntityState.Modified;

        }

        public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Where(predicate);
        }

        public IQueryable<T> GetAll()
        {
            return DbSet;
        }

        public T GetById(int id)
        {
            return DbSet.Find(id);
        }

        #endregion
    }
Community
  • 1
  • 1
Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135

2 Answers2

25

Ok, I figured this out. The reason why there isn't an Update method in new repository patterns (Entity Framework 6) is because there's no need for one. You simply fetch your record by id, make your changes and then commit/save.

For example, this is my edit POST method from my postController:

[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Edit([Bind(Include = "Id,Title,IntroText,Body,Modified,Author")] Post post)
{
    using (UnitOfWork uwork = new UnitOfWork())
    {
        Post edit = uwork.PostRepository.GetById(post.Id);
        edit.Title = post.Title;
        edit.IntroText = post.IntroText;
        edit.Body = post.Body;
        edit.Modified = DateTime.Now;

        uwork.Commit();

        return RedirectToAction("Index");
    }
}

RepositoryPattern looks like this:

public class BlogEngineRepository<T> : IRepository<T> where T : class
{
    protected DbSet<T> DbSet;

    public BlogEngineRepository(DbContext dataContext)
    {
        DbSet = dataContext.Set<T>();
    } 

    public void Insert(T entity)
    {
        DbSet.Add(entity);
    }

    public void Delete(T entity)
    {
        DbSet.Remove(entity); 
    }

    public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
    {
        return DbSet.Where(predicate);
    }

    public IQueryable<T> GetAll()
    {
        return DbSet;
    }

    public T GetById(int id)
    {
        return DbSet.Find(id);
    } 
}
Dan Beaulieu
  • 19,406
  • 19
  • 101
  • 135
  • 3
    Your repository do still have an Update method. Given your explanation, I'd guess it's not needed, isn't it? – Alisson Reinaldo Silva Jun 14 '16 at 19:11
  • @Alisson you're correct, that was a careless copy and paste. – Dan Beaulieu Jun 14 '16 at 19:13
  • 1
    Good example, bad in practice. [With EF there is no need to hit the database (select) to update object back (update)](http://stackoverflow.com/questions/11421370/efficient-way-of-updating-list-of-entities/11421706#11421706). – Erik Philips Feb 24 '17 at 00:32
  • 1
    I'm confused here because in Edit Post method we already received the object of type 'Post' with the updated values. So why do we need to call Post edit = uwork.PostRepository.GetById(post.Id); to return a new object and then fetch the post properties and assign the values ? Can't we just use what we received as the parameter ? Also how it possible to update just calling uwork.Commit(); here ? and if this is OK then why we need to have fetch the values rather than calling Commit(); only ? This may sound crazy but I'm confused – Peck_conyon Oct 21 '18 at 04:58
16

Update should look like (expanding on Dan Beaulieu's answer) :

[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Edit([Bind(Include = "Id,Title,IntroText,Body,Modified,Author")] Post post)
{
    using (UnitOfWork uwork = new UnitOfWork())
    {
        post.Modified = DateTime.Now;
        uwork.PostRepository.Update(post);

        uwork.Commit();

        return RedirectToAction("Index");
    }
}

RepositoryPattern looks like this:

public class BlogEngineRepository<T> : IRepository<T> where T : class
{
  public BlogEngineRepository(DbContext dataContext)
  {
    DbSet = dataContext.Set<T>();
    Context = dataContext;
  }

  public T Update(T entity)
  {
     DbSet.Attach(entity);
     var entry = Context.Entry(entity);
     entry.State = System.Data.EntityState.Modified;
  }
}

You can view a full explaination to the answer for Efficient way of updating list of entities for more information on the details of just an update.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • 1
    Thanks for chiming in Erik. I haven't really evaluated this pattern for a while but this seems like such an obvious win for those looking to implement an explicit `Update` method. +1 – Dan Beaulieu Feb 24 '17 at 00:44
  • A change for EF Core, EntityState.Modified can now be found in Microsoft.EntityFrameworkCore instead of System.Data – JesseTrains Jun 02 '22 at 17:51