Entity Framework (4.3.1 Code First) を使用する MVC3/.NET 4 アプリケーションがあります。
ここで説明されているように、EF を Repository/UnitOfWork パターンにラップしました…</p>
通常、記事で説明されているように、新しいレコードの作成が必要な場合、私はこれを行ってきました…</p>
public ActionResult Create(Course course)
{
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
return RedirectToAction("Index");
}
ただし、単純にレコードをデータベースに保存する以上のことが必要な場合は、IService と呼ばれるものにロジックをラップします。例えば…</p>
private ICourseService courseService;
public ActionResult Create(Course course)
{
courseService.ProcessNewCourse(course);
return RedirectToAction("Index");
}
私のサービスの 1 つで、次のようなものがあります…</p>
public void ProcessNewCourse(Course course)
{
// Save the course to the database…
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
// Generate a PDF that email some people about the new course being created, which requires more use of the unitOfWork…
var someInformation = unitOfWork.AnotherRepository.GetStuff();
var myPdfCreator = new PdfCreator();
IEnumerable<People> people = unitOfWork.PeopleRepository.GetAllThatWantNotifiying(course);
foreach(var person in people)
{
var message = “Hi ” + person.FullName;
var attachment = myPdfCreator.CreatePdf();
etc...
smtpClient.Send();
}
}
上記は実際のコードではありません (私のアプリはコースとは関係ありません。ビュー モデルを使用しており、PDF の作成と電子メール メッセージを他のクラスに分けています)。その上!
私の問題は、PDF の生成とそれを電子メールで送信するのに時間がかかることです。ユーザーは、レコードがデータベースに保存されたことを知る必要があるだけなので、 unitOfWork.Save(); の下にコードを配置すると思いました。非同期メソッドに。その後、ユーザーはリダイレクトされ、サーバーはメール、添付ファイル、および保存後に必要なその他の処理に喜んで時間を割くことができます。
これは私が苦労しているところです。
いくつか試してみましたが、現在は ICourseService で次のようになっています…</p>
public class CourseService : ICourseService
{
private delegate void NotifyDelegate(Course course);
private NotifyDelegate notifyDelegate;
public CourseService()
{
notifyDelegate = new NotifyDelegate(this.Notify);
}
public void ProcessNewCourse(Course course)
{
// Save the course to the database…
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
notifyDelegate.BeginInvoke(course);
}
private void Notify(Course course)
{
// All the stuff under unitOfWork.Save(); moved here.
}
}
私の質問/問題
「このコマンドに関連付けられた開いている DataReader が既に存在します。これを最初に閉じる必要があります。」というエラーがランダムに表示されます。Notify() メソッドで。
unitOrWork を共有しようとしているため、スレッド間で dbContext を共有しようとしているという事実と関係がありますか?
もしそうなら、なぜこれが問題なのかを説明してくれる親切な人がいますか?
UnitOfWork の新しいインスタンスを Notify メソッドに与える必要がありますか?
メソッドを非同期的に呼び出すために正しいパターン/クラスを使用していますか? それとも....の線に沿って何かを使用する必要がありますか?
新しい System.Threading.Tasks.Task(() => { Notify(コース); }).Start();
私は、非同期、並列、および並行という用語に非常に混乱していると言わざるを得ません!!
記事へのリンク (ばかのための c# async) をいただければ幸いです!!
どうもありがとう。
アップデート:
もう少し掘り下げると、この SO ページにたどり着きました: https://stackoverflow.com/a/5491978/192999と書かれています...
「ただし、EF コンテキストはスレッド セーフではないことに注意してください。つまり、複数のスレッドで同じコンテキストを使用することはできません。」
...だから私は不可能を達成しようとしていますか? これは、新しいスレッド用に新しい IUnitOfWork インスタンスを作成する必要があるということですか?