39

I need to update all fields except property1 and property2 for the given entity object.
Having this code:

    [HttpPost]
    public ActionResult Add(object obj)
    {
        if (ModelState.IsValid)
        {
                context.Entry(obj).State = System.Data.EntityState.Modified;

                context.SaveChanges();               
         }
        return View(obj);
    }

How to change it to add an exception to obj.property1 and obj.property2 for not being updated with this code?

Slauma
  • 175,098
  • 59
  • 401
  • 420
mhmd
  • 995
  • 2
  • 15
  • 30

5 Answers5

77

Let's assume that you have a collection of the properties to be excluded:

var excluded = new[] { "property1", "property2" };

With EF5 on .NET 4.5 you can do this:

var entry = context.Entry(obj);
entry.State = EntityState.Modified;
foreach (var name in excluded)
{
    entry.Property(name).IsModified = false;
}

This uses a new feature of EF5 on .NET 4.5 which allows a property to be set as not modified even after it has been previously set to modified.

When using EF 4.3.1 or EF5 on .NET 4 you can do this instead:

var entry = context.Entry(obj);
foreach (var name in entry.CurrentValues.PropertyNames.Except(excluded))
{
    entry.Property(name).IsModified = true;
}
default.kramer
  • 5,943
  • 2
  • 32
  • 50
Arthur Vickers
  • 7,503
  • 32
  • 26
  • Yeah. That's great implementation of that in .Net 4.5 – mhmd Apr 23 '12 at 07:44
  • I know this is implied, but I just wanted to explicitly state that for EF 4.3.1 - you cannot set entry.Property(...).IsModified = false; - it will compile, but you will get a runtime error when trying to do this. Therefore I think there is merit to say that for EF 4.3.1 you must use the positives only, in other words: you can only mark things as modified (true) because they are already set as not modified (false). EF 5 allows for you to freely set true/false; – dyslexicanaboko Oct 19 '12 at 17:25
  • What a great solution on .NET 4.5, I used that on IUnitOfWork + DI implementation and it's really impressive, thanks ! – Mehdi Dehghani Jul 26 '15 at 18:09
  • @Arthur - should it work like "entry.Property(obj.name).IsModified = false"? – Gautam G Mar 10 '19 at 00:52
  • 2
    Nice! Works in EF core 2.2.4 as well – Jacques May 15 '19 at 14:36
24

You can't define such an exception. You can however mark single properties as modified:

context.Entry(obj).Property(o => o.Property3).IsModified = true;
context.Entry(obj).Property(o => o.Property4).IsModified = true;
// etc.

Note that setting IsModified to false is not supported once you have marked the state of the whole entity to Modified.

For your purpose I would actually prefer to load the entity from the database and then update it using normal change tracking:

var objInDB = context.Objects.Single(o => o.Id == obj.Id);

obj.Property1 = objInDB.Property1;
obj.Property2 = objInDB.Property2;

context.Entry(objInDB).CurrentValues.SetValues(obj);

context.SaveChanges();

Note that only changed properties will be saved by default by Automatic Detect changes. See EF 6 and EF Core articles

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Slauma
  • 175,098
  • 59
  • 401
  • 420
  • 1
    I like your 2nd code block which is a nice reverse solution of not using false statement. – mhmd Apr 23 '12 at 07:47
  • 1
    +1 for the following: "Note that setting IsModified to false is not supported once you have marked the state of the whole entity to Modified." –  Oct 01 '14 at 10:26
  • 1
    I noticed a similar note here: https://msdn.microsoft.com/en-us/library/jj592677(v=vs.113).aspx that says "It is not currently possible to reset an individual property to be not modified after it has been marked as modified. This is something we plan to support in a future release." However it worked when I tried it. Maybe that msdn page is outdated, although it says it was updated October 23, 2016. – KevinVictor Apr 19 '17 at 15:30
13

This question was already nicely answered, but I wanted to provide an extension method for anyone who would like to use it.

This code was developed for EF 4.3.1

//You will need to import/use these namespaces    
using System.Data.Entity;
using System.Data.Entity.Infrastructure;    

//Update an entity object's specified columns, comma separated
//This method assumes you already have a context open/initialized
public static void Update<T>(this DbContext context, T entityObject, params string[] properties) where T : class
{
    context.Set<T>().Attach(entityObject);

    var entry = context.Entry(entityObject);

    foreach(string name in properties)
        entry.Property(name).IsModified = true;

    context.SaveChanges();
}

Usage Example

using (FooEntities context = new FooEntities())
{
    FooEntity ef = new FooEntity();

    //For argument's sake say this entity has 4 columns: 
    //    FooID (PK), BarID (FK), Name, Age, CreatedBy, CreatedOn

    //Mock changes
    ef.FooID = 1;
    ef.Name = "Billy";
    ef.Age = 85;

    context.Update<FooEntity>(ef, "Name", "Age"); //I only want to update Name and Age
}
dyslexicanaboko
  • 4,215
  • 2
  • 37
  • 43
1

This is an update that works for .net CORE and maybe can help someone who needs a generic solucion and wants to exclude some properties base on different conditions.

I'm using reflection to iterate through the properties and update base on its property value, in this case, as example, i'm excluding the null properties.

    public virtual TEntity Update(TEntity entity)
    {
        dbSet.Attach(entity);
        dbContext.Entry(entity).State = EntityState.Modified;

        var entry = dbContext.Entry(entity);

        Type type = typeof(TEntity);
        PropertyInfo[] properties = type.GetProperties();
        foreach (PropertyInfo property in properties)
        {
            if (property.GetValue(entity, null) == null)
            {
                entry.Property(property.Name).IsModified = false;
            }
        }

        dbContext.SaveChanges();
        return entity;
    }
Carlos Gregorio
  • 396
  • 3
  • 6
0

The answers above (most of them) use DbContext. For those who is using ObjectContext these solutions arent accessible.

Here is solution for ObjectContext strictly (EF5 .NET 4.5):

ctx.AddObject("ENTITYNAME", item);
ctx.ObjectStateManager.ChangeObjectState(item, EntityState.Modified);

var entry = ctx.ObjectStateManager.GetObjectStateEntry(item);
entry.RejectPropertyChanges("PROPERTY_TO_EXCLUDE");
Boppity Bop
  • 9,613
  • 13
  • 72
  • 151