2

リポジトリパターンを介してEntityFrameworkを使用していますが、重大で驚くべきパフォーマンスの問題があります。私はプロファイリングを行ったので、何が起こるかについてかなり良い考えを持っています、私はそれについて何をすべきかわからないだけです。

これが私のコードの本質です(簡略化):

var employee = Repositories.Employees.FirstOrDefault(s => s.EmployeeId == employeeId);
employee.CompanyId = null;
Repositories.Commit();

真ん中の線(employee.CompanyId = null)は、完了するまでに驚くほどの時間(約30秒)かかります。時間はコミット行に費やされません。

プロファイリングを通じて、自動生成されたEFコードのこの部分を実行する理由を見つけました。

if (previousValue != null && previousValue.**Employees**.Contains(this))
{
    previousValue.Employees.Remove(this);
}

それは本当に私を助けませんが、それは問題がEFにあることを確認します。どうしたらいいのか本当に知りたいです。他の方法(ストアドプロシージャ)で列を更新できますが、実際にはどこでもEFを使用したいと思います。

EF設定を簡単に編集できないので、これを含まない提案をしたいと思います。

更新 データベースに対してSQLを直接実行し、コンテキストからオブジェクトを更新して、EFがこの変更をすぐに検出するようにすることで、問題を解決しました。

public void SetCompanyNull(Guid employeeId)
{
    _ctx.ExecuteStoreCommand("UPDATE Employee SET CompanyId = NULL WHERE EmployeeId = N'" + employeeId + "'");
    _ctx.Refresh(RefreshMode.StoreWins, _ctx.Employees.FirstOrDefault(s => s.EmployeeId == employeeId));
}

アップデート2 また、遅延読み込みを一時的に無効にすることで問題を解決しました。

var lazyLoadDisabled = false;
if (_ctx.ContextOptions.LazyLoadingEnabled)
{
   _ctx.ContextOptions.LazyLoadingEnabled = false;
   lazyLoadDisabled = true;
}

this.GetEmployeeById(employeeId).CompanyId = null;
this.SaveChanges();

if (lazyLoadDisabled)
{
    _ctx.ContextOptions.LazyLoadingEnabled = true;
}

遅延読み込みを無効にすると、なぜこれほど高速になるのか(そして、これがどのような副作用をもたらす可能性があるのか​​)、私は本当に興味があります。

4

3 に答える 3

2

これはEFPOCOジェネレータテンプレートの問題であり、一部のシナリオで予期しない遅延読み込みが発生します。このテンプレートは、ナビゲーションプロパティの修正コードを生成するため、一方のナビゲーションプロパティを変更すると、変更されたリレーションのもう一方の端に内部的に移動し、リレーションを修正して一貫性を維持しようとします。残念ながら、関連するオブジェクトにナビゲーションプロパティが読み込まれていない場合、遅延読み込みがトリガーされます。

あなたができること:

  • テンプレートを変更し、修正に関連するすべてのコードを削除します
  • リバースナビゲーションプロパティ(Employees)をCompany
  • この操作の前に遅延読み込みをオフにしてください-context.ContextOptions.LazyLoadingEnabled = false
于 2012-05-16T14:50:57.057 に答える
0

まあ、それは奇妙です。一方、companyIdをnullに設定する代わりに、コレクションから削除してみてください。何かのようなもの;

var company = Repositories.Companies.Include("Employee").FirstOrDefault(s => s.Employee.Any(q => q.EmployeeId == employeeId));
company.Employees.Remove(q => company.Employees.Where(l => l.EmployeeId == employeeId).SingleOrDefault());
Repositories.Commit();
于 2012-05-16T14:48:43.377 に答える
0

自動変更検出に問題があります。

Ladislav Mrnkaが指摘しているように、リレーションに関係するプロパティを変更すると、その変更を関連エンティティに転送しようとします。

その操作を実行している間、コンテキストで自動「変更追跡」を無効にすることで、これを回避できます。

これは、同様の問題とその解決策を説明しています。

これは、ChanegTrackingの概念を一般的に説明しています。

于 2012-05-16T15:23:34.033 に答える