2012-04-21 8 views
29

Devo aggiornare tutti i campi tranne proprietà1 e proprietà2 per l'oggetto entità specificato.
Avendo questo codice:Come aggiornare non tutti i campi di un oggetto utilizzando Entity Framework ed EntityState.Modified

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

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

come cambiarlo aggiungere un'eccezione per obj.property1 e obj.property2 per non essere stato aggiornato con questo codice?

risposta

57

Supponiamo che si dispone di una collezione di proprietà da escludere:

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

Con EF5 su .NET 4.5 si può fare questo:

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

Utilizza una nuova funzionalità di EF5 su .NET 4.5 che consente di impostare una proprietà come non modificata anche dopo che è stata precedentemente modificata.

Quando si utilizza EF 4.3.1 o EF5 su .NET 4 si può fare questo, invece:

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

Un bel miglioramento in .NET 4.5, grazie! – Slauma

+0

Sì. Questa è una grande implementazione di questo in .Net 4.5 – mohamadreza

+0

So che questo è implicito, ma volevo solo dichiarare esplicitamente che per EF 4.3.1 - non è possibile impostare entry.Property (...). IsModified = false; - verrà compilato, ma si verificherà un errore di runtime quando si tenta di farlo. Pertanto ritengo che sia opportuno dire che per EF 4.3.1 è necessario utilizzare solo i positivi, in altre parole: è possibile contrassegnare solo le cose come modificate (true) perché sono già impostate come non modificate (false). EF 5 ti consente di impostare liberamente true/false; – dyslexicanaboko

19

Non è possibile definire tale eccezione. È tuttavia possibile contrassegnare singole proprietà come modificato:

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

Si noti che l'impostazione IsModified-false non è supportata una volta che avete segnato lo stato di tutta l'entità Modified.

per il vostro scopo avrei realtà preferiscono caricare l'entità dal database e quindi aggiornarla con una normale rilevamento delle modifiche:

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(); 
+1

Mi piace il tuo secondo blocco di codice che è una soluzione inversa bella di non utilizzare falsa dichiarazione. – mohamadreza

+1

+1 per quanto segue: "Notare che l'impostazione IsModified su false non è supportata dopo aver contrassegnato lo stato dell'intera entità su Modified." –

+0

Ho notato una nota simile qui: https://msdn.microsoft.com/en-us/library/jj592677(v=vs.113).aspx che dice "Al momento non è possibile reimpostare una singola proprietà in modo che non sia modificato dopo che è stato contrassegnato come modificato. Questo è qualcosa che pensiamo di supportare in una versione futura. " Tuttavia ha funzionato quando l'ho provato. Forse la pagina di msdn è superata, anche se dice che è stata aggiornata il 23 ottobre 2016. – KevinVictor

9

la questione è stata già ben risposto, ma ho voluto fornire un metodo di estensione per tutti coloro che vorrebbero usalo

Questo codice è stato sviluppato per 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(); 
} 

Utilizzo Esempio

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 
} 
0

Le risposte di cui sopra (la maggior parte di loro) usano DbContext. Per coloro che utilizzano ObjectContext queste soluzioni non sono accessibili.

Ecco soluzione per ObjectContext rigorosamente (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"); 
Problemi correlati