How to update record using Entity Framework Core?

Entity Framework-6.Net CoreEntity Framework-Core

Entity Framework-6 Problem Overview


What is the best approach to update database table data in Entity Framework Core?

  1. Retrieve the table row, do the changes and save
  2. Use keyword Update in DB context and handle exception for item not exist

What are the improved features we can use over EF6?

Entity Framework-6 Solutions


Solution 1 - Entity Framework-6

To update an entity with Entity Framework Core, this is the logical process:

  1. Create instance for DbContext class
  2. Retrieve entity by key
  3. Make changes on entity's properties
  4. Save changes

Update() method in DbContext:

>Begins tracking the given entity in the Modified state such that it will be updated in the database when SaveChanges() is called.

Update method doesn't save changes in database; instead, it sets states for entries in DbContext instance.

So, We can invoke Update() method before to save changes in database.

I'll assume some object definitions to answer your question:

  1. Database name is Store

  2. Table name is Product

Product class definition:

public class Product
{
	public int? ProductID { get; set; }
	
	public string ProductName { get; set; }
	
	public string Description { get; set; }
	
	public decimal? UnitPrice { get; set; }
}

DbContext class definition:

public class StoreDbContext : DbContext
{
	public DbSet<Product> Products { get; set; }
	
	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
	{
		optionsBuilder.UseSqlServer("Your Connection String");

		base.OnConfiguring(optionsBuilder);
	}
	
	protected override void OnModelCreating(ModelBuilder modelBuilder)
	{
		modelBuilder.Entity<Order>(entity =>
		{
			// Set key for entity
			entity.HasKey(p => p.ProductID);
		});
		
		base.OnModelCreating(modelBuilder);
	}
}

Logic to update entity:

using (var context = new StoreDbContext())
{
		// Retrieve entity by id
		// Answer for question #1
		var entity = context.Products.FirstOrDefault(item => item.ProductID == id);
		
		// Validate entity is not null
		if (entity != null)
		{
			// Answer for question #2

			// Make changes on entity
			entity.UnitPrice = 49.99m;
			entity.Description = "Collector's edition";
			
			/* If the entry is being tracked, then invoking update API is not needed. 
              The API only needs to be invoked if the entry was not tracked. 
              https://www.learnentityframeworkcore.com/dbcontext/modifying-data */
			// context.Products.Update(entity);
			
			// Save changes in database
			context.SaveChanges();
		}
}

Solution 2 - Entity Framework-6

According to Microsoft docs:

> the read-first approach requires an extra database read, and can result in more complex code for handling concurrency conflict

However, you should know that using Update method on DbContext will mark all the fields as modified and will include all of them in the query. If you want to update a subset of fields you should use the Attach method and then mark the desired field as modified manually.

context.Attach(person);
context.Entry(person).Property(p => p.Name).IsModified = true;
context.SaveChanges();

Solution 3 - Entity Framework-6

public async Task<bool> Update(MyObject item)
{
    Context.Entry(await Context.MyDbSet.FirstOrDefaultAsync(x => x.Id == item.Id)).CurrentValues.SetValues(item);
    return (await Context.SaveChangesAsync()) > 0;
}

Solution 4 - Entity Framework-6

It's super simple

using (var dbContext = new DbContextBuilder().BuildDbContext())
{
    dbContext.Update(entity);
    await dbContext.SaveChangesAsync();
}

Solution 5 - Entity Framework-6

Microsoft Docs gives us two approaches.

> Recommended HttpPost Edit code: Read and update

This is the same old way we used to do in previous versions of Entity Framework. and this is what Microsoft recommends for us.

Advantages

  • Prevents overposting
  • EFs automatic change tracking sets the Modified flag on the fields that are changed by form input.

> Alternative HttpPost Edit code: Create and attach

an alternative is to attach an entity created by the model binder to the EF context and mark it as modified.

As mentioned in the other answer the read-first approach requires an extra database read, and can result in more complex code for handling concurrency conflicts.

Solution 6 - Entity Framework-6

After going through all the answers I thought i will add two simple options

  1. If you already accessed the record using FirstOrDefault() with tracking enabled (without using .AsNoTracking() function as it will disable tracking) and updated some fields then you can simply call context.SaveChanges()

  2. In other case either you have entity posted to server using HtppPost or you disabled tracking for some reason then you should call context.Update(entityName) before context.SaveChanges()

1st option will only update the fields you changed but 2nd option will update all the fields in the database even though none of the field values were actually updated :)

Solution 7 - Entity Framework-6

A more generic approach

To simplify this approach an "id" interface is used

public interface IGuidKey
{
    Guid Id { get; set; }
}

The helper method

public static void Modify<T>(this DbSet<T> set, Guid id, Action<T> func)
    where T : class, IGuidKey, new()
{
    var target = new T
    {
        Id = id
    };
    var entry = set.Attach(target);
    func(target);
    foreach (var property in entry.Properties)
    {
        var original = property.OriginalValue;
        var current = property.CurrentValue;

        if (ReferenceEquals(original, current))
        {
            continue;
        }

        if (original == null)
        {
            property.IsModified = true;
            continue;
        }

        var propertyIsModified = !original.Equals(current);
        property.IsModified = propertyIsModified;
    }
}

Usage

dbContext.Operations.Modify(id, x => { x.Title = "aaa"; });

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCuriousGuyView Question on Stackoverflow
Solution 1 - Entity Framework-6H. HerzlView Answer on Stackoverflow
Solution 2 - Entity Framework-6Ehsan MirsaeediView Answer on Stackoverflow
Solution 3 - Entity Framework-6ShadamView Answer on Stackoverflow
Solution 4 - Entity Framework-6Christian FindlayView Answer on Stackoverflow
Solution 5 - Entity Framework-6NipunaView Answer on Stackoverflow
Solution 6 - Entity Framework-6Ikram ShahView Answer on Stackoverflow
Solution 7 - Entity Framework-6SimonView Answer on Stackoverflow