使用实体框架 6.1.3 进行异步分页

2024-01-08

我是 EF 的新手,所以如果有什么地方做得不对,请提前道歉。我正在努力让分页与 EF 6 异步工作。

我已经按照本文实现了分页机制:如何通过分页提高实体框架的性能 https://developingsoftware.com/entity-framework-paging/,我认为这是干净且切题的(但也不完美),但我无法让它异步工作,这是一个问题。

根据文章,我创建了界面:

public interface IPageList
{
    int TotalCount { get; }
    int PageCount { get; }
    int Page { get; }
    int PageSize { get; }
}

我创建了该类:

public class PageList<T> : List<T>, IPageList
{
    public int TotalCount { get; private set; }
    public int PageCount { get; private set; }
    public int Page { get; private set; }
    public int PageSize { get; private set; }

    public PageList(IQueryable<T> source, int page, int pageSize)
    {
        TotalCount = source.Count();
        PageCount = GetPageCount(pageSize, TotalCount);
        Page = page < 1 ? 0 : page - 1;
        PageSize = pageSize;
        AddRange(source.Skip(Page * PageSize).Take(PageSize).ToList());
    }

    private int GetPageCount(int pageSize, int totalCount)
    {
        if (pageSize == 0)
            return 0;

        var remainder = totalCount % pageSize;
        return (totalCount / pageSize) + (remainder == 0 ? 0 : 1);
    }
}

最后是扩展:

public static class PageListExtensions
{
    public static PageList<T> ToPageList<T>(this IQueryable<T> source, int pageNumber, 
    int pageSize)
    {
        return new PageList<T>(source, pageNumber, pageSize);
    }
}

所以在我的数据层中,我有以下函数:

public async Task<List<LogEntity>> GetLogsAsync(int pageNumber, int pageSize)
{
    using (_dbContext = new DatabaseContext())
    {                            
        var results = _dbContext.Logs.Select(l => new
        {
            LogId = l.LogId,
            Message = l.Message,
        })
        .OrderBy(o => o.DateTime)
        .ToPageList(pageNumber, pageSize).ToList().Select(x => new LogEntity()
        {
            LogId = x.LogId,
            Message = x.Message,
        });

        return await results.AsQueryable<LogEntity>().ToListAsync();
    }
}

当我运行上面的代码时,我得到:

附加信息:源 IQueryable 未实现 IDbAsyncEnumerable。仅来源 实现 IDbAsyncEnumerable 可用于实体框架 异步操作。欲了解更多详情,请参阅http://go.microsoft.com/fwlink/?LinkId=287068 http://go.microsoft.com/fwlink/?LinkId=287068.

我已经用谷歌搜索了这个错误,虽然我读了很多文章,但我仍然在努力让它工作。

谁能确切地告诉我如何解决这个问题,因为我现阶段不知道从哪里开始。

Thanks

UPDATE-1

正如伊万在评论中强调的那样,我认为我不需要 2Select,所以这是简化版本:

var results = _dbContext.Logs.OrderBy(o=>o.DateTime)
    .ToPageList(pageNumber, pageSize).Select(l => new
{
    LogId = l.LogId,
    Message = l.Message,
});

仍然没有解决我的异步问题。我目前正在查看这篇文章,希望对您有所帮助:

如何在异步存储库方法中返回空 IQueryable https://stackoverflow.com/questions/33305495/how-to-return-empty-iqueryable-in-an-async-repository-method

UPDATE-2

我想我已经弄清楚了,但它仍然没有像我希望的那样响应,所以我不能 100% 确定它是否正确完成。我认为当交换到 WPF 应用程序中的日志选项卡时,交换会是瞬时的,但事实并非如此!

无论如何,这是我改变的:

    public async Task<List<LogEntity>> GetLogsAsync(int pageNumber, int pageSize)
    {
        using (_dbContext = new DatabaseContext())
        {
            var results = _dbContext.Logs.OrderBy(o=>o.DateTime).ToPageList(pageNumber, pageSize).Select(l => new LogEntity
            {
                LogId = l.LogId,
                Message = l.Message,
            }).AsAsyncQueryable();

            return await results.ToListAsync();
        }
    }

如果有的话,代码肯定比我原来的代码简单。

更新3:

当我这样称呼时:

return new PageList<LogEntity>(_dbContext.Logs, pageNumber, pageSize);

它返回 TotalCount = 100,000、PageCount = 200、Page = 0、PageSize 500,但在调用 AddRange 时会抛出错误,即

发生“System.NotSupportedException”类型的异常 EntityFramework.SqlServer.dll 但未在用户代码中处理 附加信息:“Skip”方法仅支持排序 在 LINQ to Entities 中输入。必须先调用方法“OrderBy” 方法“跳过”。

所以我通过调用解决了这个问题:

return new PageList<LogEntity>(_dbContext.Logs.OrderBy(o=>o.DateTime), 
pageNumber, pageSize);

当我尝试调用 @krillgar 最简单的建议时,即

return _dbContext.Logs
       .Select(l => new LogEntity // Cast here so your .ToPageList
       { // will start as the object type you want.
         LogId = l.LogId,
         Message = l.Message    
       })
       .OrderBy(l => l.DateTime)
       .ToPageList(pageNumber, pageSize);

我收到以下错误:

发生“System.NotSupportedException”类型的异常 EntityFramework.SqlServer.dll 但未在用户代码中处理 附加信息:实体或复杂类型 无法在 LINQ to 中构造“MyCompany.DataLayerSql.LogEntity” 实体查询。

on the this.TotalCount = source.Count();在 PageList 类中。

有任何想法吗?


你正在使用async这里不正确。除非您正在执行 I/O 或非常长的操作,否则您通常只会在创建、管理和合并线程时产生额外的开销。

从数据库查询是一个 I/O 操作,但是您还没有了解实体框架的行为方式,因此您错过了使该操作异步的好处。

实体框架(以及一般的 LINQ)使用一种称为延迟执行 https://weblogs.asp.net/dixin/entity-framework-and-linq-to-entities-6-deferred-execution-laziness-loading-and-eager-loading。在这种情况下,这意味着在您想要对数据进行操作之前,不会将任何内容发送到您的数据库。您可以有条件地添加.Where(), .Skip()等等,您可以随心所欲,EF 将坐在那里准备构建 SQL 查询。

要将 SQL 语句发送到数据库,您需要act在它上面,你在你的PageList构造函数两次。第一个是:

TotalCount = source.Count();

这需要 SQL 与你所有的WHERE语句等前面加上一个SELECT COUNT (*),并获取结果。

第二次在这里:

AddRange(source.Skip(Page * PageSize).Take(PageSize).ToList());

在上面一行的末尾,.ToList()将向您的数据库发送另一个查询,检索您要求的所有列和行,并填充所有实体。THIS是你想要异步的地方,但是你不能做一个async构造函数 https://stackoverflow.com/a/8145668/1195056.

您的替代方案是放弃在构造函数中设置所有内容并使用一个方法,这可以很容易地实现async.

在你原来的问题中,你是这样开始的:

_dbContext.Logs.Select(l => new
    {
        LogId = l.LogId,
        Message = l.Message,
    })
    .OrderBy(o => o.DateTime)

此后您还更新了OrderBy() and .ToPageList()在你之前.Select()。但是,您仍然将其作为匿名对象进行查询,因此您再次需要在需要时继续进行转换。

回到问题的根源,我们需要查看您的 return 语句:

return await results.AsQueryable<LogEntity>().ToListAsync();

没有必要这样做,除了在那里放置一个人工异步调用,这不会为您节省任何东西(见上文)。你的演员表.AsQueryable<T>()只会增加处理,不会给你任何东西。

使用现有资源的最简单方法是稍微重新排列并消除冗余代码。你的.ToPageList()已经将该对象转换为List<T>,所以如果你按照正确的顺序做事,你就会避免很多悲伤:

return _dbContext.Logs
                 .Select(l => new LogEntity // Cast here so your .ToPageList
                              { // will start as the object type you want.
                                  LogId = l.LogId,
                                  Message = l.Message
                              })
                 .OrderBy(l => l.DateTime)
                 .ToPageList(pageNumber, pageSize);

这确实是您所需要的。

如果您执意要使用async,那么您应该通过添加默认构造函数和以下方法来重新设计您的类:

public async Task CreateAsync(IQueryable<T> source, int page, int pageSize)
{
    TotalCount = await source.CountAsync(); // async here would help
    PageCount = GetPageCount(pageSize, TotalCount);
    Page = page < 1 ? 0 : page - 1;
    PageSize = pageSize;
    AddRange(await source.Skip(Page * PageSize)
                         .Take(PageSize)
                         .ToListAsync()); // async here too!
}

这可以通过重构来清理,但这就是要点。然后像这样调用它:

// Get your query set up, but don't execute anything on it yet.
var results = _dbContext.Logs.Select(l => new LogEntity
                                    {
                                        LogId = l.LogId,
                                        l.Message
                                    })
                             .OrderBy(l => l.DateTime);

var pageList = new PageList<LogEntity>();
await pageList.Create(results, pageNumber, pageSize);

return pageList;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用实体框架 6.1.3 进行异步分页 的相关文章

  • c和java语言中的换行符

    现在行分隔符取决于系统 但在 C 程序中我使用 n 作为行分隔符 无论我在 Windows 还是 Linux 中运行它都可以正常工作 为什么 在java中 我们必须使用 n 因为它与系统相关 那么为什么我们在c中使用 n 作为新行 而不管我
  • std::cout 和 std::wcout 有什么区别?

    在c 中 有什么区别std cout and std wcout 它们都控制流缓冲区的输出或将内容打印到控制台 或者它们只是相似吗 它们作用于不同的字符类型 std cout uses char作为字符类型 std wcout uses w
  • 使用Physics.Raycast 和Physics2D.Raycast 检测对象上的点击

    我的场景中有一个空的游戏对象 带有 2D 组件盒碰撞器 我将脚本附加到该游戏对象 void OnMouseDown Debug Log clic 但是当我点击我的游戏对象时 没有任何效果 你有什么想法 如何检测我的盒子碰撞器上的点击 使用光
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 如何修复此错误“GDI+ 中发生一般错误”?

    从默认名称打开图像并以默认名称保存 覆盖它 我需要从 Image Default jpg 制作图形 将其放在 picturebox1 image 上并在 picurebox1 上绘制一些图形 它有效 这不是我的问题 但我无法保存 pictu
  • 将内置类型转换为向量

    我的 TcpClient 类接受vector
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 存储来自其他程序的事件

    我想将其他应用程序的事件存储在我自己的应用程序中 事件示例 打开 最小化 Word 或打开文件时 这样的事可能吗 运行程序 http msdn microsoft com en us library ms813609 aspx and 打开
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • 如何在 Blackberry Cascades 中显示具有特定号码的电话板

    我正在使用带有 C QT 和 QML 的 Blackberry Cascades 10 Beta 3 SDK 以及 Blackberry 10 Dev Alpha Simulator 和 QNX Momentics IDE 并且我正在尝试实
  • 使用 Moq 使用内部构造函数模拟类型

    我正在尝试模拟 Microsoft Sync Framework 中的一个类 它只有一个内部构造函数 当我尝试以下操作时 var fullEnumerationContextMock new Mock
  • 将 log4net 与 Autofac 结合使用

    我正在尝试将 log4net 与 Autofac 一起使用 我粘贴了这段代码http autofac readthedocs org en latest examples log4net html http autofac readthed
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • 如何从main方法调用业务对象类?

    我已将代码分为业务对象 访问层 如下所示 void Main Business object public class ExpenseBO public void MakeExpense ExpensePayload payload var
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也
  • 使用 GROUP 和 SUM 的 LINQ 查询

    请帮助我了解如何使用带有 GROUP 和 SUM 的 LINQ 进行查询 Query the database IEnumerable

随机推荐

  • C# 用户不活动的时间有多久

    一些背景 我正在编写一个具有多种表单等的应用程序 用户必须登录才能使用大部分功能 到目前为止效果很好 然而 现在 客户端请求用户在一定时间的不活动时间后注销 问题是用户仍然可以在计算机上处 于活动状态 只是不能在我的应用程序中处于活动状态
  • 具有相等填充的线性布局中的子项

    我目前正在设计一个带有 5 个按钮的 ButtonBar 它们都是 ImageButton 但目前只有 3 个 这是我的第一个 Android 项目 所以我一边做一边学习 我试图平均分配每个按钮的权重 而不缩放它们 具有相等的填充而不是相等
  • 在重新启动时保留应用程序状态

    我一直在尝试通过序列化我的主应用程序来保留 iPhone 应用程序的状态UITabBarController using NSKeyedArchiver archiveRootObject toFile 但我遇到了困难 首先我遇到了一个问题
  • 在 NetBeans 上使用 Armadillo 库编译 C++

    我将编译包含犰狳库的 C 程序 通过命令行使用以下命令可以解决此问题 g arm cpp o example O1 larmadillo 但是 当我将 O1 larmadillo 添加到 NetBeans 项目的编译选项时 出现了大量错误
  • 将 csv 导入到 iPhone 的 coredata sqlite

    如何将 csv 导入到 sqlite iPhone 的核心数据 我尝试过使用 SQLite 管理器 但它将 csv 导入到新表中 我还需要导入一些日期 那么如何将数据导入到我的sqlite数据库中呢 我有 3 个具有不同属性的实体 并且在
  • 为什么 a++++b 不起作用?

    int main int a 5 b 2 printf d a b return 0 此代码给出以下错误 错误 需要左值作为增量操作数 但如果我在整个过程中添加空格a and b 然后就可以正常工作了 int main int a 5 b
  • Android - 启动时启动服务

    从我在 Stack Exchange 和其他地方看到的一切来看 我已经正确设置了所有内容 以便在 Android 操作系统启动时启动 IntentService 不幸的是它没有在启动时启动 并且我没有收到任何错误 也许专家可以帮忙 显现
  • 通过 SVD 从基本矩阵中提取翻译的正确方法

    我校准了相机并找到了内部参数 K 我还计算了基本矩阵 F 现在 E K T F K 到目前为止 一切都很好 现在我们将基本矩阵 E 传递给 SVD 以使用分解值 U W V 来提取旋转和平移 essentialMatrix K Transp
  • 是否可以获得正在运行的进程及其符号表的核心转储?

    是否可以获取 gdb 或使用其他一些工具来创建正在运行的进程及其符号表的核心转储 如果有一种方法可以在不终止进程的情况下执行此操作 那就太好了 如果可能的话 您会使用什么命令 我正在尝试在 Linux 机器上执行此操作 Or run gco
  • WPF 列表框包装

    我有一个列表框 在其中使用 ListBox ItemsPanel WrapPanel
  • solr 建议者未返回任何结果

    我已经按照 solr wiki 文章的建议几乎到了这里 http wiki apache org solr Suggester http wiki apache org solr Suggester 我的 solrconfig xml 中有
  • 为什么 static char* 需要常量初始化,而 static char** 不需要

    有人可以解释一下为什么这段代码 main c include
  • LDIF 文件错误?无效的格式?

    我目前正在使用 UNIX 服务器上的 LDAP 我现在的主要目的是通过命令行通过 Ldapmodify 修改目录中的两个条目 这command如下 ldapmodify a D cn ldap dc cs dc ttu dc edu w p
  • 为什么 EF 6 教程使用异步调用?

    最新的 EF 教程介绍了如何将 EF 6 与 MVC 5 结合使用 似乎倾向于使用对数据库的异步调用 例如 Department department await db Departments FindAsync id 这是新标准 最佳实践
  • F# 类型提供程序和持续集成

    F 类型提供程序的类型定义通常需要常量表达式 例如对于 SQL 类型提供程序 type dbSchema SqlDataConnection lt Data Source MySqlServer Initial Catalog MyData
  • https://www.facebook.com/app_scoped_user_id/ {app_scoped_id} 重定向到 Facebook 主页 [重复]

    这个问题在这里已经有答案了 我正在使用图形 APIv2 5获取应用程序范围内的用户 ID 最近 我无法使用以下方式访问用户个人资料https www facebook com app scoped user id https www fac
  • Qt 自定义模型需要做什么才能启用 drop?

    我正在尝试在我连接的自定义模型上启用拖放功能QTreeView 我做了以下事情 确保在上启用了acceptDropsQTreeView 在我的自定义模型上实现supportedDropActions to return Qt CopyAct
  • MACOSX下jenkins用户的密码是多少?

    我正在尝试使用 TestFlight Jenkings GitHub Sonar 为 iOS iPhone 和 iPad 创建 CI 我下载了 macosx jenkings 包 向导 看来它为我的 mac 创建了一个用户 它的密码是什么
  • 为什么 Bokeh 的情节不随情节选择而改变?

    努力去理解为什么这个散景视觉效果不允许我更改绘图并查看预测数据 出现绘图和选择 下拉式 菜单 但我无法更改菜单中项目的绘图 通过 Anaconda 运行 Bokeh 1 2 0 该代码已在 Jupyter 内部和外部运行 运行代码时不会显示
  • 使用实体框架 6.1.3 进行异步分页

    我是 EF 的新手 所以如果有什么地方做得不对 请提前道歉 我正在努力让分页与 EF 6 异步工作 我已经按照本文实现了分页机制 如何通过分页提高实体框架的性能 https developingsoftware com entity fra