web-dev-qa-db-fra.com

Comment mettre à jour tous les champs d'un objet à l'aide d'Entity Framework et EntityState.Modified

J'ai besoin de mettre à jour tous les champs sauf property1 et property2 pour l'objet entité donné.
Avoir ce code:

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

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

Comment le changer pour ajouter une exception à obj.property1 et obj.property2 pour ne pas être mis à jour avec ce code?

34
mhmd

Supposons que vous ayez une collection de propriétés à exclure:

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

Avec EF5 sur .NET 4.5, vous pouvez le faire:

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

Cela utilise une nouvelle fonctionnalité d'EF5 sur .NET 4.5 qui permet de définir une propriété comme non modifiée même après qu'elle ait été précédemment définie comme modifiée.

Lorsque vous utilisez EF 4.3.1 ou EF5 sur .NET 4, vous pouvez le faire à la place:

var entry = context.Entry(obj);
foreach (var name in entry.CurrentValues.PropertyNames.Except(excluded))
{
    entry.Property(name).IsModified = true;
}
66
Arthur Vickers

Vous ne pouvez pas définir une telle exception. Vous pouvez cependant marquer des propriétés uniques comme modifiées:

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

Notez que la définition de IsModified sur false n'est pas prise en charge une fois que vous avez marqué l'état de l'entité entière sur Modified.

Pour votre objectif, je préférerais en fait charger l'entité à partir de la base de données, puis la mettre à jour en utilisant le suivi des modifications normal:

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();
21
Slauma

Cette question a déjà été bien répondu, mais je voulais fournir une méthode d'extension pour tous ceux qui souhaitent l'utiliser.

Ce code a été développé pour 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();
}

Exemple d'utilisation

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
}
9
dyslexicanaboko

Les réponses ci-dessus (la plupart d'entre elles) utilisent DbContext. Pour ceux qui utilisent ObjectContext, ces solutions ne sont pas accessibles.

Voici une solution pour ObjectContext strictement ( 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");
0
Boppity Bop