Records door één gebruiker tegelijk laten wijzigen in ASP.NET
Door Michiel van Otegem
14 april 2003
Noot: Dit artikel werkt met ASP.NET, er is ook een
ASP versie.
Op het web is er geen constante verbinding met een database. Als je een record
wilt wijzigen, moet je het eerst opvragen, waarna de databaseverbinding gesloten
wordt. Bij het opslaan wordt de database weer geopend, en wordt het record
gewijzigd. Het probleem is nu dat als iemand anders tussen het opvragen van de
gegevens en het opslaan hetzelfde record opvraagt met de bedoeling het te
wijzigen, dat er dan geen indicatie is dat iemand anders met dat record bezig is.
Het hierboven geschetste probleem kun je oplossen door slim gebruik te maken van
het Application object en het Session object. In het Application object wordt
bijgehouden welke records in gebruik zijn, en in het Session object wordt
bijgehouden welk record de gebruiker in gebruik heeft. Het makkelijkste is om
hiervoor twee functies te maken die je op verschillende plaatsen kunt gebruiken.
In ASP.NET is het handig om deze functies in een klasse op te nemen, en te voorzien
van het Shared keyword (static
in C#), zodat je de betreffende klasse niet hoeft te instantiëren.
Imports System
Imports System.Web
Namespace Aspnl.Util
Public Class RecordLocks
Shared Function LockRecord(ByVal tableName As String, ByVal primaryKey As String) As Boolean
Dim recordLocks As ArrayList
Dim context As HttpContext = HttpContext.Current
If context Is Nothing Then
Throw New Exception("Must run in a valid HTTP context")
End If
If context.Session("RecordLock") <> "" Then
Call UnlockRecord()
End If
context.Application.Lock()
Dim o As Object = context.Application("RecordLocks")
If o Is Nothing Then
recordLocks = New ArrayList()
recordLocks.Add(tableName & "|" & primaryKey & "|")
Else
recordLocks = CType(context.Application("RecordLocks"), ArrayList)
If recordLocks.IndexOf(tableName & "|" & primaryKey & "|") > -1 Then
context.Application.UnLock()
Return False 'Lock mislukt
Else
recordLocks.Add(tableName & "|" & primaryKey & "|")
End If
End If
context.Application("RecordLocks") = recordLocks
context.Application.UnLock()
context.Session("RecordLock") = tableName & "|" & primaryKey & "|"
Return True
End Function
Shared Sub UnlockRecord()
Dim recordLocks As ArrayList
Dim context As HttpContext = HttpContext.Current
If context Is Nothing Then
Throw New Exception("Must run in a valid HTTP context")
End If
context.Application.Lock()
Dim o As Object = context.Application("RecordLocks")
If o Is Nothing Then
context.Application.UnLock()
Return
End If
recordLocks = CType(context.Application("RecordLocks"), ArrayList)
recordLocks.Remove(context.Session("RecordLock"))
context.Application("RecordLocks") = recordLocks
context.Application.UnLock()
context.Session("RecordLock") = ""
End Sub
End Class
End Namespace
De bovenstaande code bevat twee functies, LockRecord
voor het verkrijgen van een record en UnlockRecord
voor het vrijgeven van een record. LockRecord geeft
True terug als het record verkregen is, en
False als het record al in gebruik is door iemand anders.
Zolang de Assembly van deze klasse beschikbaar is (bijvoorbeeld door die in
de /bin map van de applicatie te zetten), kun je de functionaliteit gebruiken
door de volledige naam (met namespace) te gebruiken. De code hieronder laat dit
zien aan de hand van gebeurtenissen die je gebruikt bij het wijzigen van records
via een DataGrid.
Sub dg_EditCommand(source As Object, e As DataGridCommandEventArgs)
Dim ProductID As String = dg.DataKeys(e.Item.ItemIndex)
If LockRecord("Products", ProductID) Then
dg.EditItemIndex = e.Item.ItemIndex
BindGrid()
Else
ErrMsg.Text = "Rij al in gebruik door andere gebruiker."
End If
End Sub
Sub DataGrid1_CancelCommand(source As Object, e As DataGridCommandEventArgs)
UnlockRecord
dg.EditItemIndex = -1
BindGrid()
End Sub
Sub dg_UpdateCommand(source As Object, e As DataGridCommandEventArgs)
...
UnlockRecord()
End Sub
Er zit nu nog een addertje onder het gras, namelijk dat een record in gebruik
blijft als iemand de browser afsluit (of naar een andere pagina gaat) voordat
het record is vrijgegeven. Om dit te voorkomen moet je in ieder geval zorgen
dat het gebruikte record vrijgegeven wordt als de sessie van de betreffende
gebruiker verloopt. Je kunt dit doen in de Session_End
gebeurtenis in global.asax.
|