私の問題
並行性をテストするための単純なWebFormsプロジェクトがあります。
使ってます:
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.
現在、同時実行性チェックに問題があります。
データを編集しているのは私だけですが、DevExpress ASPXGridViewを使用して同じレコードを2回編集すると、同時実行例外が発生します。
私が得る例外は次のとおりです:System.Data.OptimisticConcurrencyException
私のセットアップ
**簡潔にするためにここでは簡略化しています
私のコードの最初のエンティティは次のように定義されています:
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
}
[ConcurrencyCheck]属性を設定したために、concurrecnyチェックがテストされているLastUpdateという単一のフィールドを追加したことがわかります。
DevExpress ASPXGridViewを使用するWebページでは、EntityDataSourceを使用して、グリッドビューとエンティティフレームワークの間のバインディングを作成しています。グリッドビューはポップアップエディタを使用しています。私は次のイベントをフックしています:
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
}
また、直接一致テストをテストするためにいくつかのボタンイベントをフックしています。
例えば
- Get Entity
- Update Entity
- Update DB directly with sql
- Save Entity
- Get concurrency exception as expected
例えば
- Get Entity
- Update Entity
- Save Entity
- No issue.
- Get Entity again.
- Update Entity again.
- Save Entity again.
- No issue.
これらのボタンは期待どおりに機能します。グリッドの更新のみに問題があるようです。
グリッドがObjectContectを使用する必要があり、エンティティフレームワーククラスがDBContextを使用していることが原因である可能性がありますか?
私が試みた修正
私は解決策を見つけようとしてインターネットを精査しました。DevExpressフォーラムをチェックし、StackOverflowの他の投稿、インターネット上のさまざまな投稿、並行性に関するMicrosoft MSDNの記事をチェックしましたが、これを解決することはできません。
私の投稿ほど「シンプル」な投稿はありませんでした。それらはすべて他のデータが関係していた。例:マスター/詳細の関係。カスタムエディタ。など。すべてのinbuildDevExpressコントロールを使用しており、dbテーブル/エンティティに単一のグリッドビューを表示するだけです。
一部の投稿では、エンティティを更新することを提案しています。これを試しましたが、エンティティがオブジェクト状態マネージャーで追跡されていないという例外が発生します。
オブジェクトコンテキスト/データベースコンテキストを破棄して再作成することでエンティティフレームワークを更新しようとしましたが、どういうわけか、並行性の問題が発生します。
DBContexctとObjectContextを使用して更新してみました。どちらも機能しませんでした。(objContext.Refresh(RefreshMode.StoreWins、entity)。前述のように例外が発生します]エンティティが追跡されていないと言った場合、または変更されていないエンティティのみを更新するように指示した場合、何も起こりません(更新なし、例外)
DBContextをグローバルにしようとしましたが、WebFormsは、Webを更新するたびに、状態全体を再作成し、グリッドデータコンテキストなどを再フックしたいと考えているため、これは適切ではありません。(ページの読み込み、ユーザーのクリックによる編集、ユーザーのクリックによる更新)
現在、これらのソリューションはすべて、並行性の例外の後に何をすべきかを悩ませているようです。そもそも例外を取得するべきではないことを考えると、彼らは役に立たないと思います。
提案
これを機能させる方法について何か提案はありますか?
グリッドからデータを投稿した後、エンティティフレームワークを手動で更新する必要がありますか?(私は今これだけを考えました)
それは私が持っている非常に簡単なセットアップのようです。多分私は非常に明白な何かを逃しています。私はまだWebFormsやEntityFrameworkを使ったことがないので、私が見逃している単純な(そしておそらく明白な)解決策があるかもしれませんか?
助けていただければ幸いです。
ありがとうピーターメイズ