将 Asp.net 应用程序更新到 Npgsql 3 并移除 Preload Reader

Update Asp.net app to Npgsql 3 and removing Preload Reader

我已将我的 ASP.NET 应用程序从 NpgSQL 2.2.5 更新到 3.0.1。在重大更改中,指定他们已删除 Preload Reader 支持。所以我将它从字符串连接中删除。 测试我的网络应用程序时,我在 linq 查询 中得到了错误 "An operation is already in progress.",如下所示:

 var plugins =
            from p in _pluginRepository.GetPlugins() // this method return this: GetAll().OrderBy(p => p.Created)
            join e in _userPluginRepository.GetByUserId(user.Id).ToList() on p.Id equals e.Plugin.Id into pe
            from e in pe.DefaultIfEmpty()
            select new PluginViewModel
            {
                Active = e != null,
                Name = p.Translations.ToUserLanguage(loggedInUser),
                Key = p.Key,
                PluginId = p.Id,
                SettingId = e == null ? 0 : e.Id,
                ExpireDate = e != null && e.ExpireDate.HasValue ? e.ExpireDate.Value : (DateTime?) null,
                Grants = e == null ? UserPluginGrants.None.GetHashCode().ToString() : e.Grants.GetHashCode().ToString()
            };

为了解决这个错误,我必须在 GetPlugins 方法之后附加一个 ToList。 这是在没有 Preload Reader 的情况下使用的正确行为吗?为什么?

在 Npgsql 2.x 中,使用 Preload Reader 使 Npgsql 将查询的整个结果集从数据库中拉入应用程序的内存中。这释放了连接并允许执行另一个命令,同时仍然遍历第一个查询的结果集。换句话说,它允许您像可以同时执行多个查询一样进行编程(有时称为 MARS),尽管在幕后实现效率低下。

添加 ToList() 做完全相同的事情 - 将所有内容都拉入客户端内存,只是它发生在您的应用程序代码中而不是数据库驱动程序中。因此,将您的应用程序从 Npgsql 2.x 移植到 3.x.

绝对是一种可接受的方式

现在,如果拉取的结果集(在本例中为 GetPlugins)很小,这是一种完全有效的方法。如果它很大,那么您应该研究替代方案。在您的示例中,连接可以发送到数据库,使您的 Linq 表达式转换为单个 SQL 查询并消除对多个查询的需要(诸如 Entity Framework 之类的 ORM 通常可以为您完成此操作) .更极端的解决方案是使用多个数据库连接,但如果您使用的是事务,那会更重并且也会有问题。

请注意,在 Npgsql 中实现真正的 MARS 存在一个问题(尽管不太可能很快实现):https://github.com/npgsql/npgsql/issues/462