Ho qualche prodotto in vendita e voglio verificare l'esistenza del prodotto in negozio. Io uso Entity Framework e SQL server. Voglio che alcuni la pensino così.
IF ((SELECT TOP 1 Amount FROM tblProduct WHERE Id =1)>0)
UPDATE tblProduct
SET count = count -1
WHERE Id = 1
Ma questo non è in una transazione e quando gli utenti vogliono comprare nello stesso tempo, non posso controllarlo correttamente. Ho provato questo:
BEGIN TRANSACTION
IF ((SELECT TOP 1 Amount FROM tblProduct WHERE Id =1)>0)
UPDATE tblProduct
SET count = count -1
WHERE Id = 1
COMMIT
ma non è vero. Come posso farlo nel quadro di entità. Grazie
Come ho capito, stai cercando di ridurre il numero di prodotti su ogni operazione di vendita. È necessario farlo atomicamente perché è necessario evitare di vendere un prodotto esaurito.
Esistono diverse opzioni come il blocco ottimistico con la versione mantenuta sui dati o il blocco distribuito per fornire un'operazione di acquisto su un articolo.
In SQL puoi eseguire la dichiarazione di aggiornamento con le versioni come di seguito:
update [table]
set count = count - 1
where id=1 and count=5 and version=3
Ogni aggiornamento blocca la riga, quindi se un'altra richiesta di aggiornamento arriva in azione attende l'aggiornamento corrente e quando viene eseguita ha effetto su 0 righe.
È inoltre possibile utilizzare un blocco distribuito con redis e bloccare il processo stesso.
Dipende da requisiti, casi d'uso e risorse.
Per fare ciò usando il framework di entità, se si utilizza il codice per primo si può fare l'approccio seguente:
// add the below property to your entity
[Timestamp]
public byte[] RowVersion { get; set; }
con api fluenti:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<YourEntity>().Property(s => s.RowVersion).IsConcurrencyToken();
//modelBuilder.Entity<YourEntity>().Property(s => s.RowVersion).IsRowVersion(); // in EF6 or EF Core
base.OnModelCreating(modelBuilder);
}
Oppure puoi usare l'attributo [ConcurrencyCheck] :
[ConcurrencyCheck]
public int Version { get; set; }
[ConcurrencyCheck]
public int Count { get; set; }
EF aggiungerà queste colonne alla condizione in cui si trovano le query di aggiornamento. Se il numero di righe interessate è pari a 0 EF, DbUpdateConcurrencyException deve essere rilevato .
Dai un'occhiata a ulteriori informazioni:
https://docs.microsoft.com/en-us/ef/core/modeling/concurrency
Concorrenza ottimistica: IsConcurrencyToken e RowVersion
https://www.codeproject.com/Articles/817432/Optimistic-Concurrency-in-Entity-Framework-Code-Fi
http://www.binaryintellect.net/articles/14e67064-634c-4206-9eca-a42d3739594a.aspx
Puoi provare altri modi per implementarlo. Ad esempio, esegui solo l'aggiornamento, quando c'è quantità:
UPDATE tblProduct
SET count = count -1
WHERE Id = 1
AND Amount > 0;
In questo modo, non c'è bisogno dall'istruzione select
. In alternativa, è possibile aggiungere un check constraint
per garantire che il count
sia sempre > 0
e lasciare che Motore SQL applichi le proprietà ACID. Se in qualche modo, un utente (transazione) tenta di ridurre il conteggio inferiore a 0, verrà generato un errore e sarà possibile rilevare l'errore nell'applicazione (ad esempio).