- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Concurrency issues
Joined: 30-Nov-2005
Hi everyone,
I am new user to LLBLGen and I think its a great product. I am trying to get simple concurrency working using a MS SQL Server timestamp column. I have read the many posts on this forum regarding concurrency but still have problems getting it to work.
The code is as follows, In the Entity class I have included this private class,
Private Class CustomerConcurrencyPredicateFactory
Implements IConcurrencyPredicateFactory
Public Function CreatePredicate( _
ByVal predicateTypeToCreate As ConcurrencyPredicateType, ByVal containingEntity As Object) _
As IPredicateExpression Implements IConcurrencyPredicateFactory.CreatePredicate
Dim toReturn As IPredicateExpression = New PredicateExpression
Dim customer As Test1Entity = CType(containingEntity, Test1Entity)
'''''''''''''''''''''''''
Select Case predicateTypeToCreate
Case ConcurrencyPredicateType.Delete
Case ConcurrencyPredicateType.Save
' only for updates
toReturn.Add(PredicateFactory.CompareValue( _
Test1FieldIndex.Ts, _
ComparisonOperator.Equal, _
customer.Fields(CType(Test1FieldIndex.TimeStampColumn, Integer)).CurrentValue))
End Select
Return toReturn
End Function
End Class
Also in the Entity class I have added this method to call the CreatePredicate method, BTW I was planning in putting this call in a more automated place once I have it working, e.g. during the save function.
Public Sub AddPredicate()
Dim CPF As New CustomerConcurrencyPredicateFactory
CPF.CreatePredicate(ConcurrencyPredicateType.Save, Me)
Me.ConcurrencyPredicateFactoryToUse = CPF
End Sub
From the PL I create an instance of the entity for one record
Dim newValues As New DAL.EntityClasses.Test1Entity("1")
Change the record in Enterprise manager, then update the Test1Entity column
newValues.Col1 = Me.TextBox1.Text
Save the updated entity
Dim boolSavedRecord As Boolean = adapter.SaveEntity(newValues)
If boolSavedRecord Then
MessageBox.Show("Saved")
Else
MessageBox.Show("Not Saved")
End If
However, even though the updated newValues record does not get written to the table, SaveEntity always returns true. I dont get any Exception at all.
Thanks,
Sean
Could you set a breakpoint in CreatePredicate and see if it is hit? Also, could you enable DQE tracing (see 'Troubleshooting and debugging' in the documentation) to see what the query is that's been generated so you can check if the query contains the timestamp restriction?
Joined: 30-Nov-2005
Hi Otis,
I have set a breakpoint and CreatePredicate does get executed.
I have also run the SQL Server profiler to see what the database is receiving, the produced update statement does produce a where clause with the timestamp value to compare, I tested the produced update statement in query analyiser and the update does fail with a record count of zero.
PS I have also ensured the global nocount setting in the SQL Server configuration is unticked, I noticed you suggested that to someone on another thread.
But I will have a read of the DQE tracing in the docs and see what I can find out from that.
Thanks,
Sean
Joined: 30-Nov-2005
Ok I got the Concurrency exception to throw , I will explain what was happening,
The flow of my test application is,
1). Load Entity values from database, 2). Update a column in the entity, 3). Attempt to update record to database.
Between steps 1 & 2 above I change the database record outside of the application.
Now at step 2 where I update the entity column, if this value was the same as what was first read, the IsDirty property = False.
So at this stage the entities value is now different from what is now in the database record.
I now attempt to save the entity using
adapter.SaveEntity
The output of the DQE Trace is
Method Enter: DataAccessAdapterBase.SaveEntity(4) Method Enter: DataAccessAdapterBase.DetermineActionQueues(4) Method Exit: DataAccessAdapterBase.DetermineActionQueues(4) Method Exit: DataAccessAdapterBase.SaveEntity(4): no entities to save.
The save does not happen, but adapter.SaveEntity does returns True i.e a successful save.
Of course if I change the entity column to a new value, then attempt to save, I then get the Concurrency error.
So the question is,
Even though the stored entity has not changed, if the application did attempt to write this same record back to the database and this record has since been updated by another user, should adapter.SaveEntity return a successful save status ?
PS, I did attempt to set the entities IsDirty property = True when no change was made , This generate these DQE messages
Method Enter: DataAccessAdapterBase.SaveEntity(4) Method Enter: DataAccessAdapterBase.DetermineActionQueues(4) Method Exit: DataAccessAdapterBase.DetermineActionQueues(4) Method Enter: DataAccessAdapterBase.StartTransaction Method Enter: DataAccessAdapterBase.OpenConnection Method Exit: DataAccessAdapterBase.OpenConnection Method Exit: DataAccessAdapterBase.StartTransaction Method Enter: DataAccessAdapterBase.PersistQueue Method Exit: DataAccessAdapterBase.PersistQueue Method Enter: DataAccessAdapterBase.PersistQueue Method Enter: CreateUpdateDQ(5)
So it looks like an update to the database was attempted, but according the SQL Profiler no UPDATE statement was sent to the DB. Sean
Seanw wrote:
Ok I got the Concurrency exception to throw , I will explain what was happening,
The flow of my test application is,
1). Load Entity values from database, 2). Update a column in the entity, 3). Attempt to update record to database.
Between steps 1 & 2 above I change the database record outside of the application.
Now at step 2 where I update the entity column, if this value was the same as what was first read, the IsDirty property = False.
So at this stage the entities value is now different from what is now in the database record.
I now attempt to save the entity using
adapter.SaveEntity
The output of the DQE Trace is
Method Enter: DataAccessAdapterBase.SaveEntity(4) Method Enter: DataAccessAdapterBase.DetermineActionQueues(4) Method Exit: DataAccessAdapterBase.DetermineActionQueues(4) Method Exit: DataAccessAdapterBase.SaveEntity(4): no entities to save.
The save does not happen, but adapter.SaveEntity does returns True i.e a successful save.
aha! I was under the assumption you did change a value in the entity as you posted earlier a query was sent to the database (so I assumed an actual query was generated and executed)
Of course if I change the entity column to a new value, then attempt to save, I then get the Concurrency error.
So the question is,
Even though the stored entity has not changed, if the application did attempt to write this same record back to the database and this record has since been updated by another user, should adapter.SaveEntity return a successful save status ?
Yes, because there's nothing to save, and it was decided that a save action with nothing to save should report 'true', not 'false' which would indicate a failure. THe reason for this is that if you perform saves in a loop or in a generic routine, you probably don't want to jump out of it and handle a failure which technically isn't a failure.
Because for the 'reality' the entity in memory is in, it hasn't been changed and therefore won't be saved or better: there won't be a save action on the database.
PS, I did attempt to set the entities IsDirty property = True when no change was made , This generate these DQE messages
Method Enter: DataAccessAdapterBase.SaveEntity(4) Method Enter: DataAccessAdapterBase.DetermineActionQueues(4) Method Exit: DataAccessAdapterBase.DetermineActionQueues(4) Method Enter: DataAccessAdapterBase.StartTransaction Method Enter: DataAccessAdapterBase.OpenConnection Method Exit: DataAccessAdapterBase.OpenConnection Method Exit: DataAccessAdapterBase.StartTransaction Method Enter: DataAccessAdapterBase.PersistQueue Method Exit: DataAccessAdapterBase.PersistQueue Method Enter: DataAccessAdapterBase.PersistQueue Method Enter: CreateUpdateDQ(5)
So it looks like an update to the database was attempted, but according the SQL Profiler no UPDATE statement was sent to the DB. Sean
Correct, as no field was found which was changed so no query is generated. Please set one field's IsChanged flag to true as well and you'll see an update query. Because nothing was changed in your original attempt, the code doesn't know which UPDATE statement to generate as there's nothing to update, hence the fact that it simply returns with 'nothing to save'.