2010-11-18 14 views
79

Diciamo che interrogo il database e carico un elenco di elementi. Quindi apro uno degli elementi in un modulo di visualizzazione dettagli e invece di interrogare nuovamente l'elemento fuori dal database, creo un'istanza dell'elemento dall'origine dati nell'elenco.Aggiornare un record senza prima eseguire una query?

C'è un modo per aggiornare il record del database senza recuperare il record del singolo elemento?

Ecco un esempio di come sto facendo ora:

dataItem itemToUpdate = (from t in dataEntity.items 
           where t.id == id 
           select t).FirstOrDefault(); 

Poi dopo aver tirato la cronaca io aggiornare alcuni valori della voce e spingere il disco posteriore:

itemToUpdate.itemstatus = newStatus; 
dataEntity.SaveChanges(); 

penserei ci sarebbe un modo migliore per farlo, qualche idea?

+2

Non è un modo terribilmente cattivo o fare le cose. Hai accesso concorrente a quel tavolo? –

+0

Penso che questo sia l'uso che un ORM come EF è esattamente lì per servire. Per consentire alle operazioni nel contesto dell'applicazione di essere eseguite sugli oggetti che si desidera creare/modificare/eliminare, senza preoccuparsi dell'implementazione del DB sottostante? –

+27

Penso che per gli sviluppatori con un background in TSQL che cercano di accettare e abbracciare gli ORM, è un po 'inefficiente cercare un record solo per aggiornarlo e non utilizzare mai i dati recuperati. Questo concetto che uno sviluppatore non ha bisogno di preoccuparsi dell'implementazione del database sottostante è un crock. Più uno sviluppatore conosce l'intero sistema, migliore è la soluzione. Le opzioni non sono mai una brutta cosa. – barrypicker

risposta

61

È necessario utilizzare il metodo Attach().

Attaching and Detaching Objects

+13

puoi fornire un esempio? –

+14

context.Products.Attach (prodotto); context.Entry (prodotto) .State = EntityState.Modified; – Gabriel

+4

@Gabriel Non aggiornerà comunque tutte le proprietà? Cosa succede se voglio modificare solo uno? –

0

In generale, se è stato utilizzato Entity Framework per interrogare tutti gli elementi, e salvato l'oggetto entità, è possibile aggiornare i singoli elementi nel oggetto entità e chiamare SaveChanges() quando si è finito. Ad esempio:

var items = dataEntity.Include("items").items; 
// For each one you want to change: 
items.First(item => item.id == theIdYouWant).itemstatus = newStatus; 
// After all changes: 
dataEntity.SaveChanges(); 

Il recupero dell'elemento desiderato non deve generare una nuova query.

+0

Risposta interessante, qualcun altro ha confermato questo? – Ian

+3

Questo ha lo stesso problema di OP: recupera l'intero record, quindi lo aggiorna. .First() deserializza l'oggetto. – Jerther

27

È anche possibile utilizzare l'SQL diretto sul database utilizzando il contesto del datastore. Esempio:

dataEntity.ExecuteStoreCommand 
    ("UPDATE items SET itemstatus = 'some status' WHERE id = 123 "); 

Per motivi di prestazioni, è possibile passare le variabili anziché una singola stringa SQL codificata. Ciò consentirà a SQL Server di memorizzare nella cache la query e riutilizzare i parametri. Esempio:

dataEntity.ExecuteStoreCommand 
    ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 }); 

UPDATE - per EF 6,0

dataEntity.Database.ExecuteSqlCommand 
     ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 }); 
+6

perché dovresti effettuare il downgrade della risposta senza lasciare un commento. Questo suggerimento si rivolge alla domanda degli autori originali. – barrypicker

+11

'ExecuteStoreCommand' non è proprio un modo per farlo, usa semplicemente' DbConnection' contenuto in 'DbContext' per eseguire un comando. Non è indipendente dal database, per non parlare dell'agnostico della persistenza (ad esempio, questo esempio si arresterebbe in modo anomalo se l'OP passasse a XML). –

+7

@ just.another.programmer: con grande potere derivano grandi responsabilità. – barrypicker

6

Se il DataItem ha campi EF sarà pre-validate (come i campi non annullabili), dovremo disattivare che la convalida per questo contesto:

DataItem itemToUpdate = new DataItem { Id = id, Itemstatus = newStatus }; 
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true; 
dataEntity.Configuration.ValidateOnSaveEnabled = false; 
dataEntity.SaveChanges(); 
//dataEntity.Configuration.ValidateOnSaveEnabled = true; 

Altrimenti possiamo cercare di soddisfare la pre-validazione e ancora aggiornare solo la singola colonna:

DataItem itemToUpdate = new DataItem 
{ 
    Id = id, 
    Itemstatus = newStatus, 
    NonNullableColumn = "this value is disregarded - the db original will remain" 
}; 
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true; 
dataEntity.SaveChanges(); 

Supponendo dataEntity è un System.Data.Entity.DbContext

è possibile verificare esimo e di query generato aggiungendo questo al DbContext:

/*dataEntity.*/Database.Log = m => System.Diagnostics.Debug.Write(m); 
3

Il codice:

ExampleEntity exampleEntity = dbcontext.ExampleEntities.Attach(new ExampleEntity { Id = 1 }); 
exampleEntity.ExampleProperty = "abc"; 
dbcontext.Entry<ExampleEntity>(exampleEntity).Property(ee => ee.ExampleProperty).IsModified = true; 
dbcontext.Configuration.ValidateOnSaveEnabled = false; 
dbcontext.SaveChanges(); 

Il risultato TSQL:

exec sp_executesql N'UPDATE [dbo].[ExampleEntities] 
SET [ExampleProperty ] = @0 
WHERE ([Id] = @1) 
',N'@0 nvarchar(32),@1 bigint',@0='abc',@1=1 

Nota:

Il "IsModified = true" linea, è necessaria perché quando si crea il nuovo oggetto ExampleEntity (solo con la proprietà Id popolata) tutte le altre proprietà hanno i loro valori predefiniti (0, null, ecc.). Se si desidera aggiornare il DB con un "valore predefinito", la modifica non verrà rilevata dal framework di entità e quindi DB non verrà aggiornato.

Nell'esempio:

exampleEntity.ExampleProperty = null; 

non funziona senza la linea "IsModified = true", perché l'ExampleProperty proprietà, è già nullo quando è stato creato l'oggetto ExampleEntity vuoto, si ha bisogno di dire a EF che questo la colonna deve essere aggiornata, e questo è lo scopo di questa linea.

Problemi correlati