2012-03-08 17 views
11

La mia tabella Sections (SQL Server) ha (int, identity) come chiave primaria (int, identity) e SortIndex colonna (int) per scopi di ordinamento.Entity Framework non aggiorna il valore modificato da un trigger

Il database ha un trigger che imposta SortIndex := ID a ogni INSERT. Ovviamente voglio cambiare l'indice di ordinamento in seguito, scambiando i valori per due righe.

Accedo ai dati utilizzando Entity Framework, il tutto con l'applicazione Web MVC3.

Il problema è che Entity Framework non aggiorna il valore di SortIndex dopo aver inserito un nuovo oggetto nella tabella. Inoltre memorizza nella cache tutti i dati, quindi la seguente chiamata per ottenere tutti gli oggetti da questa tabella fornirà anche il valore SortIndex errato per questo oggetto.

Ho provato a cambiare StoreGeneratedPattern per questa colonna in EDMX. Questo sembra essere grande ed elegante ma non risolve il problema.

Se impostato su Identity, fa sì che EF aggiorni correttamente il valore, ma diventa di sola lettura (eccezione generata quando si prova a cambiare). Impostarlo su Computed è simile, ma invece di essere lanciati i valori non vengono scritti nel DB.

posso ricreare l'oggetto EF ogni volta che se ho bisogno di usarlo dopo aver inserito un oggetto, solo facendo:

DatabaseEntities db = new DatabaseEntities() 

ma sembra brutto soluzione per me.

Qual è la soluzione a questo problema?

Ovviamente qualcosa, quello che non mi richiede di fare qualche azione dopo ogni insert (e rischiare che sia dimenticato e inosservato) è preferito.

+0

Eventuali duplicati: http://stackoverflow.com/questions/5445243/reload-field-value-modified-in-db-by-trigger-after-insert-update –

+0

È simile, ma sembra che abbia un campo su cui non ha bisogno di scrivere. "Calcolato" dovrebbe andare bene per lui. Semplicemente non funziona a causa di qualche bug. – Arek

risposta

15

In breve StoreGeneratedPattern significa: il valore viene gestito dal negozio e l'applicazione non lo modificherà mai. In tal caso, il valore generato automaticamente verrà generato automaticamente dopo aver chiamato SaveChanges.

Se non si utilizza StoreGeneratedPattern non si otterrà il valore e sarà necessario forzare un'altra esecuzione di query per aggiornare la propria entità. È possibile ad esempio fare:

objectContext.Refresh(RefreshMode.StoreWins, yourSection); 

Generalmente le situazioni in cui è necessario aggiornare i valori sia in banca dati attraverso i trigger e l'applicazione non giocano molto bene con EF (e probabilmente anche altri strumenti ORM).

+0

Grazie per il codice "Aggiorna", sembra migliore di ricreare l'oggetto EF. Purtroppo non posso votare con la mia reputazione. – Arek

+0

@Arek è possibile accettare la risposta –

+0

So che posso accettare, ma sto testando alcune altre possibili soluzioni qui, quindi non ancora. – Arek

0

Sapete se lavorerete ancora con quella colonna nella stessa richiesta?

Vorrei utilizzare lo scenario contesto per richiesta, che di solito ti mette fuori da molti problemi, perché un nuovo contesto EF viene creato con ogni richiesta, quindi hai una nuova dati una volta per richiesta.

Con un contesto di lunga durata, è possibile aumentare le incostanze come descritto.

Ad ogni modo lo StoreGeneratedPattern impostato per il calcolo dovrebbe essere corretto. Ma si aggiorna solo quando stai memorizzando l'entità reale. Non viene aggiornato inserendo o aggiornando qualsiasi altra entità.

da http://msdn.microsoft.com/en-us/library/dd296755(v=vs.90).aspx

Se si crea una nuova entità o modificare un'entità esistente, i valori delle proprietà con StoreGeneratedPattern impostate Computerizzata vengono recuperati dal server quando si chiama il metodo SaveChanges nell'applicazione. Se si assegna un valore a una proprietà con StoreGeneratedPattern impostato su Calcolato nell'applicazione, il valore verrà sovrascritto con il valore generato dal server quando si chiama il metodo SaveChanges.

Stiamo utilizzando l'opzione di valore calcolato per GUID sequenziato SQL e funziona correttamente.

+0

Quello che sto facendo è (1) aggiungere un nuovo oggetto, (2) ottenere e restituire tutti gli oggetti ordinati da SortIndex per aggiornare la pagina web. Quindi sì, sto usando ancora SortIndex nella stessa richiesta. – Arek

+0

And StoreGeneratedPattert = Computed - questo sembra aggiornare correttamente l'oggetto, ma non posso più modificare SortIndex. Ci provo, ma dopo che ho salvato i vecchi valori di SaveChanges(). Sembra che l'EF ignori tranquillamente questi cambiamenti. – Arek

+0

Sì, storeGenerated dice chiaramente che è stato generato nell'archivio, quindi non si preoccupa di scriverlo. Forse per te sarà meglio impostare entity.SortIndex = entity.id subito dopo il salvataggio, quindi puoi lavorarci come vorresti probabilmente. –

2

Ho trovato la risposta di "Ladislav Mrnka" esatta e contrassegnata come accettata. Ecco altre soluzioni alternative, che ho trovato durante il tentativo di trovare qualche soluzione. Tuttavia, la soluzione che stavo cercando in generale non è possibile.

Una delle possibilità è impostare StoreGeneratedPattern = Computed in modo che EF sappia, questo valore viene calcolato. Quindi, eseguire una stored procedure per modificare effettivamente il valore di SortIndex. Normalmente cambierebbe i valori in due righe (scambiali), per cambiare l'ordine di ordinamento. Questa procedura insieme a un trigger su INSERT garantisce che i dati rimangano coerenti nel DB. Non è possibile creare una nuova riga senza il valore corretto impostato in SortIndex, non è possibile fare in modo che due oggetti abbiano lo stesso valore (a meno che la stored procedure non abbia un bug) e non sia possibile interrompere manualmente il valore in qualche modo, perché non è possibile modificare attraverso EF. Sembra un'ottima soluzione.

È facilmente possibile avere procedure memorizzate associate a funzioni in EF.

Il problema è che ora è possibile inserire una nuova riga e EF aggiorna correttamente i dati nella sua cache, ma la cache non viene aggiornata dopo aver chiamato la stored procedure. Sono comunque necessarie alcune funzioni di aggiornamento manuale o di aggiornamento. Altrimenti la seguente chiamata per ottenere oggetti ordinati per SortIndex darà risultati errati.

Oltre a ciò, è possibile impostare MergeOption = MergeOption.OverwriteChanges per diverse entità, il che fa sì che EF aggiorni i dati dal DB in qualche modo meglio. A questo punto, è possibile rileggere l'oggetto dopo averlo inserito o richiamato la stored procedure e verrà aggiornato. Tuttavia, la lettura di una raccolta di oggetti con db.Section.OrderBy(o => o.SortIndex) restituirà comunque risultati memorizzati nella cache con un ordine di ordinamento errato.

Se qualcuno è interessato, è possibile fare MergeOption predefinito a qualcosa d'altro con l'aggiunta di EF classe parziale e quindi il metodo parziale OnContextCreated, come qui:

public partial class DatabaseEntities 
{ 
    partial void OnContextCreated() 
    { 
     Subsection.MergeOption = MergeOption.OverwriteChanges; 
     Section.MergeOption = MergeOption.OverwriteChanges; 
     Function.MergeOption = MergeOption.OverwriteChanges; 
    } 
} 
+0

Grazie, funziona per me !!! – Rodrigo

Problemi correlati