我有一个使用Entity Framework(4.3.1 Code First)的MVC3 / .NET 4应用程序
我已将EF包装到Repository / UnitOfWork模式中,如此处所述......
通常,正如文章中所解释的那样,当我需要创建新记录时,我一直在这样做......
public ActionResult Create(Course course)
{
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
return RedirectToAction("Index");
}
然而,当不仅仅需要将记录保存到数据库时,我将逻辑包装到我称之为IService的内容中。例如......
private ICourseService courseService;
public ActionResult Create(Course course)
{
courseService.ProcessNewCourse(course);
return RedirectToAction("Index");
}
在我的一项服务中,我有以下内容......
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中有以下内容......
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这一事实有关?
如果是这样,有人可以帮助解释为什么这是一个问题吗?
我是否应该向Notify方法提供unitOfWork的新实例?
我是否使用正确的模式/类来异步调用该方法?或者我应该使用......的内容......
new System.Threading.Tasks.Task(()=&gt; {Notify(course);})。Start();
我必须说我对异步,并行和并发这两个术语感到非常困惑!
任何文章的链接(c#async for idiots)都将不胜感激!!
非常感谢。
更新:
更多的挖掘让我看到了这个SO页面:https://stackoverflow.com/a/5491978/192999说...
“请注意,虽然EF上下文不是线程安全的,即您不能在多个线程中使用相同的上下文。”
...所以我试图实现不可能的事情吗?这是否意味着我应该为我的新线程创建一个新的IUnitOfWork实例?
答案 0 :(得分:0)
您可以创建一个轮询后台线程,该线程与主流分开执行冗长的操作。此线程可以扫描数据库以查找新项目(或标记为要处理的项目)。这个解决方案非常简单,即使您的应用程序崩溃也可以确保完成作业(当轮询线程再次启动时它将被拾取)。
如果请求“丢失”,如果您的应用程序在请求文档之后以及生成/发送之前崩溃,那么您也可以使用Synchronised Queue。
有一件事几乎可以肯定 - 正如 rikitikitik 所说 - 你将需要使用一个新的工作单元,这意味着一个单独的交易。