My Issue
I have a simple WebForms project for testing concurrency.
I am using:
1. Entity Framework 4.3.1 code first approach.
2. DevExpress ASP.net controls to visualize my data. Specifically an ASPXGridView control.
3. MySQL as database backend.
Now I am having an issue with the concurrency check.
Even if I am the only user editing the data, if I edit the same record twice using the DevExpress ASPXGridView I get a concurrency exception!
The exception I get is : System.Data.OptimisticConcurrencyException
My Setup
** Simplified here for brevity
My code first entity is defined something like this:
public class Country
{
//Some constructors here
[Required, ConcurrencyCheck]
public virtual string LastUpdate { get; set; }
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public virtual int CountryID { get; set; }
//Various other data fields here
}
You can see I have added a single field called LastUpdate which the concurrecny check is being tested against due to setting the [ConcurrencyCheck] attribute.
On my web page with the DevExpress ASPXGridView I am using an EntityDataSource to make the binding between the grid view and the entity framework. The grid view is using a popup editor. I have the following events hooked:
protected void Page_Load(object sender, EventArgs e)
{
//Hook entity datasource to grid view
dbgCountries.DataSource = CountriesEntityDataSource;
dbgCountries.DataBind();
}
protected void CountriesEntityDataSource_ContextCreating(object sender, EntityDataSourceContextCreatingEventArgs e)
{
//Create and hook my DBContext class to the entity
//datasources ObjectContext property.
var context = new MyDBContextClass();
e.Context = ((IObjectContextAdapter)context ).ObjectContext;
}
protected void dbgCountries_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
//I create a new MyDBContextClass here and use it
//to get the next free id for the new record
}
protected void dbgCountries_CustomErrorText(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomErrorTextEventArgs e)
{
//My code to catch the System.Data.OptimisticConcurrencyException
//excpetion is in here.
//I try to rtefresh the entity here to get the latest data from
//database but I get an exception saying the entity is not being
//tracked
}
protected void dbgCountries_RowValidating(object sender, DevExpress.Web.Data.ASPxDataValidationEventArgs e)
{
//Basic validation of record update in here
}
protected void dbgCountries_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
//I set the LastUpdate field (my concurrency field)
//to the current time here
}
I also have some button events hooked to test a direct concurrecny test.
eg
- Get Entity
- Update Entity
- Update DB directly with sql
- Save Entity
- Get concurrency exception as expected
eg
- Get Entity
- Update Entity
- Save Entity
- No issue.
- Get Entity again.
- Update Entity again.
- Save Entity again.
- No issue.
These buttons work as expected. Only ther grid updates seem to have an issue.
Maybe it is because the grid needs to use ObjectContect and my entity framework classes are using DBContext?
My Attempted Fixes
I have scoured the internet trying to find a solution. Checked DevExpress forums, checked other posts here on StackOverflow, various posts on the internet, Microsoft MSDN articles on concurrency and I just can not work this out.
None of the posts were as 'simple' as mine. They all had other data involved. eg a master/detail relashionship. custom editors. etc. I am using all inbuild DevExpress controls and just display a single grid view on my db table / entity.
Some posts suggest refreshing the entities. I tried this but get an exception saying the entity is not being tracked in the object state manager.
I tried refreshing the entity framework by destroying and recreating my object context / db context but somehow I still get the concurrency issue.
I tried refreshing using the DBContexct and also the ObjectContext. Neither worked. (objContext.Refresh(RefreshMode.StoreWins, entity). I either get an exception as stated] earlier sayign the entity is not being tracked, or if I tell it to refresh only non modifed entities then nothing happens at all (no refresh, no excpetion)
I tried making my DBContext global but this is no good as WebForms appears to want to recreate its entire state and rehook its grids data context etc after every web refresh. (page loads, user clicks edit, user clicks ok to update)
Now all of these solutions seem to takle what to do AFTER the concurrency exception. Seeing that I should not even be getting the exception in the first place I guess they would not help.
Suggestions
Do any of you have suggestions on how to make this work?
Do I have to maybe force the entity framework to refresh manually after posting data from the grid? (I only just thought of this one now)
It seems a pretty simple setup I have. Maybe I am missing something very obvious. I have not worked with WebForms or EntityFramework much yet so there could be simple (and perhaps obvious) solutions I am missing?
Any help appreciated.
Thanks Peter Mayes