entity frameworkSaveChanges()与SaveChangesAsync()和Find()与FindAsync()
我一直在寻找2对以上的差异,但没有find任何文章解释清楚,以及何时使用这个或那个。
那么SaveChanges()
和SaveChangesAsync()
什么区别呢?
和Find()
和FindAsync()
?
在服务器端,当我们使用Async
方法时,我们也需要添加await
。 因此,我不认为它是服务器端的asynchronous。
这是否有助于防止客户端浏览器上的UI阻塞? 或者他们之间有什么优点和缺点?
无论何时您需要在远程服务器上执行操作,程序都会生成请求,发送请求,然后等待响应。 我将使用SaveChanges()
和SaveChangesAsync()
作为示例,但Find()
和FindAsync()
同样适用。
假设你有一个需要添加到你的数据库的100+项目的myList
列表。 为了插入,你的函数看起来像这样:
using(var context = new MyEDM()) { context.MyTable.AddRange(myList); context.SaveChanges(); }
首先创buildMyEDM
实例,将MyEDM
列表myList
到MyTable
表MyTable
,然后调用SaveChanges()
以将更改保存到数据库中。 它的工作方式是你想要的,logging被提交,但是你的程序不能做任何事情,直到提交完成。 这可能需要很长时间,具体取决于您所做的事情。 如果您正在对logging进行更改,那么实体必须一次提交这些更改(我曾经保存2分钟才能更新)!
要解决这个问题,你可以做两件事情之一。 首先是你可以启动一个新的线程来处理插入。 虽然这将释放调用线程继续执行,但是您创build了一个正在坐在那里等待的新线程。 没有必要开销,这就是async await
模式解决的问题。
对于I / O操作, await
很快成为你最好的朋友。 从上面的代码部分,我们可以修改它是:
using(var context = new MyEDM()) { Console.WriteLine("Save Starting"); context.MyTable.AddRange(myList); await context.SaveChangesAsync(); Console.WriteLine("Save Complete"); }
这是一个非常小的变化,但是对代码的效率和性能有深远的影响。 那么会发生什么? 代码的MyEDM
是相同的,你创build一个MyEDM
的实例, MyEDM
添加到MyTable
。 但是当你调用await context.SaveChangesAsync()
,代码的执行返回到调用函数! 所以当你在等待所有这些logging提交时,你的代码可以继续执行。 说包含上面代码的函数具有public async Task SaveRecords(List<MyTable> saveList)
的签名,调用函数可以是这样的:
public async Task MyCallingFunction() { Console.WriteLine("Function Starting"); Task saveTask = SaveRecords(GenerateNewRecords()); for(int i = 0; i < 1000; i++){ Console.WriteLine("Continuing to execute!"); } await saveTask; Console.Log("Function Complete"); }
为什么你会有这样的function,我不知道,但它输出显示如何async await
工作。 首先让我们看看发生了什么。
执行进入MyCallingFunction
, Function Starting
然后Save Starting
被写入到控制台,然后函数SaveChangesAsync()
被调用。 此时,执行返回到MyCallingFunction
并进入for循环写入“继续执行”达1000次。 当SaveChangesAsync()
结束时,执行返回到SaveRecords
函数,将Save Complete
写入控制台。 一旦SaveRecords
所有SaveRecords
完成, SaveRecords
执行就会在SaveChangesAsync()
完成时继续执行。 困惑? 这是一个输出示例:
function启动 保存开始 继续执行! 继续执行! 继续执行! 继续执行! 继续执行! .... 继续执行! 保存完成! 继续执行! 继续执行! 继续执行! .... 继续执行! function完成!
或者可能:
function启动 保存开始 继续执行! 继续执行! 保存完成! 继续执行! 继续执行! 继续执行! .... 继续执行! function完成!
这是async await
之美的美妙之处,你的代码可以继续运行,而你正在等待一些完成。 在现实中,你将会有一个更像这样的函数作为你的调用函数:
public async Task MyCallingFunction() { List<Task> myTasks = new List<Task>(); myTasks.Add(SaveRecords(GenerateNewRecords())); myTasks.Add(SaveRecords2(GenerateNewRecords2())); myTasks.Add(SaveRecords3(GenerateNewRecords3())); myTasks.Add(SaveRecords4(GenerateNewRecords4())); await Task.WhenAll(myTasks.ToArray()); }
在这里,你有四个不同的保存loggingfunction在同一时间 。 如果单独SaveRecords
函数,则SaveRecords
将使用async await
更快地完成。
我还没有涉及的一件事就是await
关键字。 这样做是停止执行当前函数,直到您正在等待的任何Task
完成。 因此,在原来的SaveRecords
的情况下,直到SaveRecords
函数完成后, Function Complete
行将不写入控制台。
长话短说,如果你有一个select使用async await
,你应该,因为它会大大提高你的应用程序的性能。
这个陈述是不正确的:
在服务器端,当我们使用asynchronous方法时,我们也需要添加await。
你不需要添加“等待”。 “await”只是C#中的一个方便的关键字,它使您能够在调用之后编写更多的代码行,而其他行将在Save操作完成后才会执行。 但正如您所指出的那样,只需调用SaveChanges而不是SaveChangesAsync即可完成该操作。
但从根本上说,asynchronous调用远不止于此。 这里的想法是,如果在保存操作正在进行时您可以执行其他工作(在服务器上),那么您应该使用SaveChangesAsync。 不要使用“等待”。 只要调用SaveChangesAsync,然后继续并行执行其他的东西。 这可能包括在Web应用程序中,甚至在“保存”完成之前向客户端返回响应。 但是,当然,您仍然需要检查Save的最终结果,以防万一失败,您可以将其传达给您的用户,或以某种方式logging下来。