2012-04-19 12 views
7

Ho un vincolo univoco su una colonna della tabella Navigations denominata Index. Ho due entità Navigation e voglio scambiare i loro valori Index.Scambio di valori con vincolo univoco in Entity Framework

Quando chiamo db.SaveChanges genera un'eccezione che indica che un vincolo univoco è stato violato. Sembra che EF stia aggiornando un valore e poi l'altro, violando così il vincolo.

Non dovrebbe aggiornarli entrambi in una transazione e quindi provare a eseguire il commit una volta che i valori sono stati ordinati e non in violazione del vincolo?

C'è un modo per aggirare questo senza utilizzare valori temporanei?

+1

Potrebbe mostrare come codice? – Likurg

+0

qui sono necessari i valori temporanei, un aggiornamento è un'operazione autonoma. in modo da ottenere sempre una violazione del vincolo, l'unica altra opzione è disabilitare i vincoli per l'operazione. –

risposta

9

Non è un problema di EF ma il problema del database SQL perché i comandi di aggiornamento vengono eseguiti in sequenza. La transazione non ha nulla a che fare con questo: tutti i vincoli sono convalidati per comando non per transazione. Se si desidera scambiare valori univoci, sono necessari ulteriori passaggi in cui verranno utilizzati valori fittizi aggiuntivi per evitare questa situazione.

+0

Questo sembra pericoloso a causa del potenziale per i problemi di presentare richieste concorrenti che utilizzano lo stesso valore fittizio, o forse un valore fittizio che viola anche il vincolo. Esiste una "best practice" per questa situazione che conosci? –

+1

È inoltre possibile eliminare vecchi record e crearne di nuovi. Cercherò di evitare questo, in primo luogo.È una situazione in cui il vincolo univoco non si adatta alle esigenze della logica dell'applicazione. –

+0

Abbastanza giusto. Sto solo andando a rimuovere il vincolo univoco dal database. Non causerà problemi se ci sono duplicati. Se ci sono, saranno solo in un ordine inaffidabile quando visualizzati su una barra di navigazione. –

2

È possibile eseguire una query SQL personalizzata per scambiare i valori, in questo modo:

update Navigation 
set valuecolumn = 
     case 
      when id=1 then 'value2' 
      when id=2 then 'value1' 
     end 
where id in (1,2) 

Tuttavia, Entity Framework non possono farlo, perché è al di fuori della portata di un ORM. Esegue semplicemente le istruzioni sequenziali update per ciascuna entità modificata, come Ladislav descritto nella sua risposta.

Un'altra possibilità potrebbe essere quella di eliminare il vincolo UNIQUE nel database e fare affidamento sull'applicazione per applicare correttamente questo vincolo. In questo caso, l'EF potrebbe salvare le modifiche bene, ma a seconda del tuo scenario, potrebbe non essere possibile.

3

Ci sono alcuni approcci. Alcuni di essi sono trattati in altre risposte e commenti, ma per completezza, li elencherò qui di seguito (si noti che questo è solo un elenco che ho analizzato e potrebbe non essere tutto ciò che è "completo").

  1. Eseguire tutti gli aggiornamenti in un unico comando. Vedi W0lf's answer per un esempio di questo.
  2. Esegui due serie di aggiornamenti: una per scambiare tutti i valori con il valore negativo del valore previsto e poi un secondo per scambiarli da negativo a positivo. Questo sta lavorando sull'ipotesi che i valori negativi non siano impediti da altri vincoli e che non siano valori che registreranno dati diversi da quelli in uno stato transitorio.
  3. Aggiungere una colonna aggiuntiva - IsUpdating ad esempio - impostarlo su true nel primo set di aggiornamenti in cui i valori vengono modificati e quindi impostarlo su false in una seconda serie di aggiornamenti. Sostituire il vincolo univoco per un indice univoco filtrato che ignora i record in cui IsUpdating è true.
  4. Rimuovere il vincolo e gestire i valori duplicati.
+0

L'idea di impostare su negativo e poi su positivo è stata intelligente e ha fatto il trucco per me. Grazie! – jslatts