c# - Conditions fails when 2 user are doing the delete action -
my problem pretty straightforward, have page admins can manage list of authorized admin problem there should @ least 1 admin left in database wrote simple if checks number of admins in database should higher 1 before deleting
here controller delete action
public actionresult deleteadmin(int idadmin) { using (inscriptionformationentities dbm = new inscriptionformationentities()) { administrateurs admin = dbm.administrateurs.firstordefault(x => x.id == idadmin); if(admin.nomlogin == session["utilisateur"].tostring()) { modelstate.addmodelerror("current user", "you can't delete yourself"); } if(dbm.administrateurs.tolist().count <= 1) { modelstate.addmodelerror("lastadmin", "at least 1 admin must left"); } if (modelstate.isvalid) { dbm.administrateurs.remove(admin); dbm.savechanges(); } list<administrateurs> listeadmin = dbm.administrateurs.tolist(); return redirecttoaction("utilisateurs", "admin"); } } this code works fine expect in 1 case : if there 2 admin left , try delete eachother @ same time able to. tried change put condition(for instance before delete) still condition returns false. wondering if there way prevent defining 1 instance can delete @ time or that.
edit
i looked question: how can lock table on read, using entity framework?
but dosen't solve problem because don't want lock on read on delete instead, because if lock read 1 person able access page @ time ( work in worse case scenario hope there better solution)
if willing use stored procedures use sp_getapplock. works mutex in stored procedure. in protected code section record count , delete knowing call procedure not execute code until lock released.
i have added example procedure, ignore set @msg , raiserror statements these there display status, important bit starts @ exec statement.
run procedures in 2 separate tabs, both start second wait 15 seconds acquire lock , continue if gets it.
exec critical_rhz '00:00:20' simulates process take 20 seconds
create proc dbo.critical_rhz @wait_duration varchar(30) = '00:01:00' -- default 1 minute /* performs task in critical section of code can run 1 session or transaction @ time. task simulated wait raiseerror() nowait real time status displays */ declare @rc int = 0 -- return code , @msg varchar(2000) set @msg = convert(varchar,getdate(), 114) + ' critical_section_worker starting' raiserror (@msg, 0, 1) nowait begin try begin tran set @msg= convert(varchar,getdate(), 114) + ' requesting lock' raiserror (@msg, 0, 1) nowait exec @rc = sp_getapplock @resource='criticalsectionworker' -- resource locked , @lockmode='exclusive' -- type of lock , @lockowner='transaction' -- transaction or session , @locktimeout = 15000 -- timeout in milliseconds, 15 seconds set @msg= convert(varchar,getdate(), 114) + ' sp_getapplock returned ' + convert(varchar(30), @rc) + ' -- ' + case when @rc < 0 'could not obtain lock' else 'lock obtained' end raiserror (@msg, 0, 1) nowait if @rc >= 0 begin set @msg= convert(varchar,getdate(), 114) + ' got lock starting critical work ' raiserror (@msg, 0, 1) nowait waitfor delay @wait_duration -- critical work simulated waiting commit tran -- release lock set @msg= convert(varchar,getdate(), 114) + ' work complete released lock' raiserror (@msg, 0, 1) nowait end else begin rollback tran set @rc = 50000 end end try begin catch set @msg = 'error: ' + error_message() + ' @ ' + coalesce(error_procedure(), '') + coalesce (' line:' + convert(varchar(30), error_line()), '') raiserror (@msg, 0, 1) nowait -- ensure message gets out if @@trancount > 1 rollback tran raiserror (@msg, 16, 1) end catch return @rc go
Comments
Post a Comment