Domanda

Ho giocato con Entity Framework e finora mi piace usarlo molto. Ma tutto ciò che ho fatto finora assume un blocco ottimistico che funziona bene per me nella maggior parte dei casi. Tuttavia, ho il seguente scenario:

  1. Una tabella SQL Server con solo una riga che contiene dati a livello dell'applicazione
  2. La riga contiene una colonna denominata "NextAvailableNumber"
  3. L'applicazione deve leggere il numero, incrementarlo per 1 e aggiornarlo

Quanto sopra deve garantire che qualsiasi processo concorrente debba attendere per ottenere un numero fino al completamento della prima transazione. In precedenza l'abbiamo fatto usando i blocchi della tabella (dato che esiste solo una riga), ma vorrei sapere come dovrebbe essere fatto usando LINQ alle entità?

Grazie,

Jim K.

È stato utile?

Soluzione

Penso che tu debba implementarlo nella procedura memorizzata perché e utilizzare il blocco delle righe esplicite (o il blocco della tabella come hai detto). Quindi chiamerai quella procedura da EF. Non penso che questo possa essere gestito dal codice dell'applicazione a meno che tu non stia utilizzando una transazione serializzabile ogni volta che lavori con la tua tabella speciale. Può avere un enorme impatto negativo sulle prestazioni dell'applicazione.

In realtà stiamo facendo qualcosa di simile, ma la nostra tabella contiene molte righe per sequenze diverse, quindi sto usando la procedura memorizzata con il blocco delle righe e il blocco di aggiornamento. Per prima cosa volevamo chiamare questa procedura nel metodo di inserimento del nostro repository, ma successivamente l'ho spostata nel database e chiamo la mia procedura da After Insert Trigger. La ragione di ciò era quella di Deffer Row Blocco al momento dell'inserimento reale al database non al momento di contrassegnare l'entità per l'inserto nel contesto EF (inserire se stessa e la chiamata di procedura deve trovarsi nella stessa transazione nel nostro caso). Ho modificato il mio modello EF in modo che la proprietà correlata abbia StoreGeneratedPattern impostato su calcolato. Dopo ogni inserto, EF richiederà DB per ottenere il numero di sequenza assegnato. L'unico inconveniente è che EF richiederà anche DB dopo ogni aggiornamento di queste entità, ma nel nostro caso lo fa già a causa del timestamp. Questo è ancora in fase di test e valutazione in modo da poter ancora cambiare idea e reimpregnarlo.

Altri suggerimenti

Esiste un'altra soluzione che stiamo utilizzando e puoi utilizzare per evitare di utilizzare le procedure di archivio, specialmente se si utilizza il codice EF prima come noi. Il codice prima non supporta l'uso delle procedure dell'archivio.

La soluzione sta utilizzando il metodo SQLQuery di EF all'interno dell'ambito della transazione, è necessario scrivere una query che prima eseguire un aggiornamento del contatore del numero successivo, quindi selezionarlo. Il codice sarà:

string query = "UPDATE Registre_Counter SET Counter = Counter + 1 WHERE CounterName = @p0 AND Year = @p1;";
query += "select * from Registre_Counter Where CounterName = @p0 AND Year = @p1";

GenericCounter GenericCounter = CoreDBContext.Instance().GenericCounter.SqlQuery(query, new Object[] { _counterName, _year }).SingleOrDefault(); //Updates the counter and return de NextNumber to Use

L'aggiornamento bloccerà il contatore ed eviterà le letture da altre transazioni su di esso fino a quando il transaccion non viene interrotto o impegnato.

Poiché Entity Framework utilizza un blocco ottimistico, lancerà un'eccezione quando il numero successivo viene modificato da un secondo processo. Il modo più primitivo per contrastare questa situazione sarà prendere l'eccezione e rifare il cambiamento fino a quando il cambiamento avrà successo. [È possibile aggiungere un timeout a questo per garantire che l'esecuzione del codice passi avanti nello scenario peggiore

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top