1

I have this class that I use for DB operations:

public class EntityService<TEntity> : IRepository<TEntity> where TEntity : BaseModel { ApplicationDbContext _context; private DbSet<TEntity> _entities; public EntityService() { _context = new ApplicationDbContext(); } public virtual void Update(TEntity entity) { if (entity == null) throw new ArgumentNullException(nameof(entity)); try { var dbEnt = _context.Set<TEntity>().Where(c => c.Id == entity.Id).First(); dbEnt = entity; dbEnt.UpdatedBy = GetCurrentUser(); dbEnt.DateUpdated = DateTime.Now; _context.SaveChanges(); } catch (DbUpdateException exception) { throw new Exception(GetFullErrorTextAndRollbackEntityChanges(exception), exception); } //-----other methods for insert and get working fine---- } 

There are also other methods in this class for insert and get are working fine. Only this update method is not updating the entity and not throwing the exception.

UPDATE

I am facing similar problem but opposite in functioning here: Add() method adding duplicate rows for linked models in Code-First Entity Framework

I think these two have same reason of Change Tracking. But one is adding other is not updating.

14
  • 1
    if you want update entity why you again get it and put entity in dbEnt? Commented May 25, 2019 at 7:20
  • @hassan.ef It was not working when I did that. So I thought if I get the database entity again from the database then _context will have its db reference. Because entity is just method parameter. Commented May 25, 2019 at 7:22
  • I think at first you should update parameter of dbEnt with parameter of entity like this: for example: edbEnt.Name = entity.Name and dont use dbEnt = entity. Commented May 25, 2019 at 7:26
  • @hassan.ef This is a common method to update all the entities. I can't explicitly assign individual property here. Commented May 25, 2019 at 7:29
  • Before saving, you could try calling context.Entry(entity).State=EntityState.Modified;. Commented May 25, 2019 at 7:43

4 Answers 4

4

The line...

var dbEnt = _context.Set<TEntity>().Where(c => c.Id == entity.Id).First(); 

...attaches an entity object to the context and returns a reference to this entity.

Then the line...

dbEnt = entity; 

...replaces this reference by a reference to the entity variable that enters the method. That is not the tracked entity object. You basically lost the reference to the tracked entity and it's impossible to change it any longer.

You should either attach entity to the context and mark it as modified, or get dbEnt as you already do and modify and save that object. Both methods have pros and cons, see here.

Sign up to request clarification or add additional context in comments.

Comments

1
+100

After getting entity from _context, update all fields from new detail and set entity state to modified

var dbEnt = _context.Set<TEntity>().Where(c => c.Id == entity.Id).First(); dbEnt.Name = entity.Name; ... ... ... dbEnt.UpdatedBy = GetCurrentUser(); dbEnt.DateUpdated = DateTime.Now; _context.Entry(dbEnt).State = EntityState.Modified; _context.SaveChanges(); 

1 Comment

Setting State = EntityState.Modified is not necessary, I'd even say not recommended.
0

If you have found your entity via Id

var dbEnt = _context.Set<TEntity>().Where(c => c.Id == entity.Id).First(); 

then why this line?

dbEnt = entity; 

Remove the above line as it will remove the reference to the tracked object.

Comments

-1

Thank you everyone. I received a lots of hint from your answers. As @GertArnold and @Colonel Software's answer hinted me I modified my code like this and it worked:

//Assigning BaseModel properties entity.CreatedBy = dbEnt.CreatedBy; entity.UpdatedBy = GetCurrentUser(); entity.DateUpdated = DateTime.Now; entity.DateCreated = dbEnt.DateCreated; //Changing entity states _context.Entry(dbEnt).State = EntityState.Detached; _context.Entry(entity).State = EntityState.Modified; _context.SaveChanges(); 

11 Comments

Why not just modify and save dbEnt as happens in the answer you refer to?
@GertArnold Tried that but it is showing duplicate primary key values exception. I will try solving that later but for now it is working and I need to deliver the project soon so I have to go for this solution. Thank you for your help I learned a lot from your answer and +1 to it.
Downvote for what? This solves my issue. May be it's not the best solution but it is a solution.
Then you did more than you show. As said in another answer (and mine), all you need is remove dbEnt = entity;.
The downvote is because your code barely happens to work. Using AddOrUpdate here is pretty weird.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.