实体框架 SaveChanges() 与 SaveChangesAsync() 和 Find() 与 FindAsync() [英] Entity Framework SaveChanges() vs. SaveChangesAsync() and Find() vs. FindAsync()

查看:38
本文介绍了实体框架 SaveChanges() 与 SaveChangesAsync() 和 Find() 与 FindAsync()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找上述 2 对之间的差异,但没有找到任何文章清楚地解释它以及何时使用一个或另一个.

那么 SaveChanges()SaveChangesAsync() 有什么区别?
Find()FindAsync() 之间?

在服务器端,当我们使用Async方法时,我们还需要添加await.因此,我不认为它在服务器端是异步的.

它是否仅有助于防止客户端浏览器上的 UI 阻塞?或者它们之间有什么优缺点?

解决方案

任何时候您需要在远程服务器上执行操作,您的程序都会生成请求、发送请求,然后等待响应.我将使用 SaveChanges()SaveChangesAsync() 作为示例,但同样适用于 Find()FindAsync().

假设您有一个包含 100 多个项目的列表 myList,需要添加到您的数据库中.要插入它,您的函数将如下所示:

using(var context = new MyEDM()){上下文.MyTable.AddRange(myList);context.SaveChanges();}

首先创建MyEDM 的实例,将列表myList 添加到表MyTable,然后调用SaveChanges() 将更改持久化到数据库.它以您想要的方式工作,记录被提交,但您的程序在提交完成之前不能做任何其他事情.这可能需要很长时间,具体取决于您提交的内容.如果您要提交对记录的更改,实体必须一次提交这些更改(我曾经有一次保存需要 2 分钟才能更新)!

要解决此问题,您可以执行以下两项操作之一.首先是您可以启动一个新线程来处理插入.虽然这将释放调用线程以继续执行,但您创建了一个新线程,它将坐在那里等待.不需要这种开销,这就是 async await 模式解决的问题.

对于 I/O 操作,await 很快就会成为您最好的朋友.从上面的代码部分,我们可以将其修改为:

using(var context = new MyEDM()){Console.WriteLine("保存开始");上下文.MyTable.AddRange(myList);等待 context.SaveChangesAsync();Console.WriteLine("保存完成");}

这是一个很小的变化,但会对代码的效率和性能产生深远的影响.那么会发生什么?代码的开头是相同的,您创建一个 MyEDM 实例并将您的 myList 添加到 MyTable.但是当您调用 await context.SaveChangesAsync() 时,代码的执行返回到调用函数!因此,当您等待所有这些记录提交时,您的代码可以继续执行.假设包含上述代码的函数具有public async Task SaveRecords(List saveList)的签名,调用函数可能如下所示:

公共异步任务 MyCallingFunction(){Console.WriteLine("函数启动");任务 saveTask = SaveRecords(GenerateNewRecords());for(int i = 0; i <1000; i++){Console.WriteLine("继续执行!");}等待保存任务;Console.Log("功能完成");}

为什么会有这样的函数,我不知道,但它的输出显示了 async await 是如何工作的.首先让我们回顾一下会发生什么.

执行进入MyCallingFunctionFunctionStarting然后SaveStarting被写入控制台,然后函数SaveChangesAsync() 被调用.此时,执行返回到MyCallingFunction 并进入for 循环写入'Continuing to Execute' 最多1000 次.SaveChangesAsync() 完成后,执行返回到 SaveRecords 函数,将 Save Complete 写入控制台.SaveRecords 中的所有内容完成后,将在 MyCallingFunction 中继续执行,就像 SaveChangesAsync() 完成时一样.使困惑?这是一个示例输出:

<前>功能启动保存开始继续执行!继续执行!继续执行!继续执行!继续执行!....继续执行!保存完成!继续执行!继续执行!继续执行!....继续执行!功能齐全!

或者也许:

<前>功能启动保存开始继续执行!继续执行!保存完成!继续执行!继续执行!继续执行!....继续执行!功能齐全!

这就是 async await 的美妙之处,您的代码可以在您等待某事完成时继续运行.实际上,您将有一个更像这样的函数作为您的调用函数:

公共异步任务 MyCallingFunction(){列表<任务>myTasks = new List();myTasks.Add(SaveRecords(GenerateNewRecords()));myTasks.Add(SaveRecords2(GenerateNewRecords2()));myTasks.Add(SaveRecords3(GenerateNewRecords3()));myTasks.Add(SaveRecords4(GenerateNewRecords4()));等待 Task.WhenAll(myTasks.ToArray());}

在这里,您有四种不同的保存记录功能同时运行.MyCallingFunction 使用 async await 的完成速度比串行调用单个 SaveRecords 函数要快得多.

我还没有涉及的一件事是 await 关键字.这样做是停止当前函数的执行,直到您等待的任何 Task 完成.因此,在原始 MyCallingFunction 的情况下,在 SaveRecords 函数完成之前,不会将 Function Complete 行写入控制台.

长话短说,如果您可以选择使用 async await,您应该这样做,因为它会大大提高您的应用程序的性能.

I have been searching for the differences between 2 pairs above but haven't found any articles explaining clearly about it as well as when to use one or another.

So what is the difference between SaveChanges() and SaveChangesAsync()?
And between Find() and FindAsync()?

On server side, when we use Async methods, we also need to add await. Thus, I don't think it is asynchronous on server side.

Does it only help to prevent the UI blocking on client side browser? Or are there any pros and cons between them?

解决方案

Any time that you need to do an action on a remote server, your program generates the request, sends it, then waits for a response. I will use SaveChanges() and SaveChangesAsync() as an example but the same applies to Find() and FindAsync().

Say you have a list myList of 100+ items that you need to add to your database. To insert that, your function would look something like so:

using(var context = new MyEDM())
{
    context.MyTable.AddRange(myList);
    context.SaveChanges();
}

First you create an instance of MyEDM, add the list myList to the table MyTable, then call SaveChanges() to persist the changes to the database. It works how you want, the records get committed, but your program cannot do anything else until the commit finishes. This can take a long time depending on what you are committing. If you are committing changes to the records, entity has to commit those one at a time (I once had a save take 2 minutes for updates)!

To solve this problem, you could do one of two things. The first is you can start up a new thread to handle the insert. While this will free up the calling thread to continue executing, you created a new thread that is just going to sit there and wait. There is no need for that overhead, and this is what the async await pattern solves.

For I/O opperations, await quickly becomes your best friend. Taking the code section from above, we can modify it to be:

using(var context = new MyEDM())
{
    Console.WriteLine("Save Starting");
    context.MyTable.AddRange(myList);
    await context.SaveChangesAsync();
    Console.WriteLine("Save Complete");
}

It is a very small change, but there are profound effects on the efficiency and performance of your code. So what happens? The begining of the code is the same, you create an instance of MyEDM and add your myList to MyTable. But when you call await context.SaveChangesAsync(), the execution of code returns to the calling function! So while you are waiting for all those records to commit, your code can continue to execute. Say the function that contained the above code had the signature of public async Task SaveRecords(List<MyTable> saveList), the calling function could look like this:

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");
}

Why you would have a function like this, I don't know, but what it outputs shows how async await works. First let's go over what happens.

Execution enters MyCallingFunction, Function Starting then Save Starting gets written to the console, then the function SaveChangesAsync() gets called. At this point, execution returns to MyCallingFunction and enters the for loop writing 'Continuing to Execute' up to 1000 times. When SaveChangesAsync() finishes, execution returns to the SaveRecordsfunction, writing Save Complete to the console. Once everything in SaveRecords completes, execution will continue in MyCallingFunction right were it was when SaveChangesAsync() finished. Confused? Here is an example output:

Function Starting
Save Starting
Continuing to execute!
Continuing to execute!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Save Complete!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Function Complete!

Or maybe:

Function Starting
Save Starting
Continuing to execute!
Continuing to execute!
Save Complete!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Function Complete!

That is the beauty of async await, your code can continue to run while you are waiting for something to finish. In reality, you would have a function more like this as your calling function:

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());
}

Here, you have four different save record functions going at the same time. MyCallingFunction will complete a lot faster using async await than if the individual SaveRecords functions were called in series.

The one thing that I have not touched on yet is the await keyword. What this does is stop the current function from executing until whatever Task you are awaiting completes. So in the case of the original MyCallingFunction, the line Function Complete will not be written to the console until the SaveRecords function finishes.

Long story short, if you have an option to use async await, you should as it will greatly increase the performance of your application.

这篇关于实体框架 SaveChanges() 与 SaveChangesAsync() 和 Find() 与 FindAsync()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆