“当不存在数据时尝试读取无效。”,但“hasrows”为真

Posted

技术标签:

【中文标题】“当不存在数据时尝试读取无效。”,但“hasrows”为真【英文标题】:"Invalid attempt to read when no data is present.", but "hasrows" is true 【发布时间】:2021-10-24 14:57:00 【问题描述】:

我想知道是否有人可以解释为什么我没有在这段代码中获取数据:

Private Sub RecoverUnsentOrderToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles RecoverUnsentOrderToolStripMenuItem.Click
        ' Find orders for this branch with status = "1" - created but not acked from the server

        Dim myxDBReader As SqlDataReader
        Dim myxDBcmd As SqlCommand
        Dim query As String

        query = "select * from orders where branch = @branch and status = 1;"
        myxDBCmd = New SqlCommand(query, myDBCnn)
        myxDBcmd.Parameters.Add("@branch", SqlDbType.VarChar).Value = BranchCode
        myxDBReader = myDBCmd.ExecuteReader
        If myxDBReader.HasRows Then
            Do While myxDBReader.Read
                Stop
            Loop
        End If

BranchCode 和我的数据库连接是公共变量。当我运行此代码时,它会到达“停止”并停止,但是当我尝试使用结果时,例如在即时窗口中通过尝试? myxdbreader(0).tostring,我得到“无效的尝试读取时间没有数据存在”例外。当我将鼠标悬停在myxdbreader 上查看结果时,我得到了行列表,但看不到其中的数据。

这是一个相当大的(对我来说,但不是庞大的)VB 应用程序,它执行各种查询并毫无问题地检索数据。该代码是从代码的另一部分复制和粘贴的,它工作得很好。数据库连接是一个单一的,在应用程序启动时打开并根据需要传递。应用程序的另一部分使用相同的数据库连接毫无问题地写入此“订单”表。

我有另一个工具条菜单功能,除了查询之外,它在所有方面都是相同的,在这种情况下它很简单

select * from linkstatus where id=1

这也有同样的问题 - 在 do while dbreader.read 循环内停止,因此它显然找到了一行,但不允许我以通常的方式访问数据。

因为它到达了“停止”,我知道HasRows 确实是真的,而且它似乎已经读取了第一行。我能看到唯一不同的是,这段代码是从我今天添加到表单中的菜单运行的,而所有其余代码都是从主表单上的各种按钮运行的。

我在所有地方都查看了该错误消息,这似乎是因为人们没有执行“读取”。

这是来自 Visual Studio 2019 的 vb.net,正在访问 SQL Server 2018。

【问题讨论】:

数据阅读器只能转发。将鼠标悬停在它上面看到有行的那一刻,枚举就完成了,它不再可用。根据您的调试器所做的事情(例如在没有提示的情况下自动评估本地人),实际上可能无法以这种方式查看行。如果您首先在代码中分配列,然后中断并检查该值,您应该会看到它。另外,如果我没有提到 Dapper 作为自己编写这种样板代码的替代方法,那我将是失职,这也将避免急切枚举的问题。 “数据库连接是单一的,在应用程序启动时打开并根据需要传递”。不要那样做。这不是 ADO.NET 的设计用途。在您创建命令的位置创建连接。打开连接,获取数据,关闭连接并丢弃它。这就是设计者想要使用 ADO.NET 的方式。 这段代码中的一个大红旗(不确定是否与您看到的内容有任何关系,但仍然存在)是myDBCnn 没有在方法本身中声明和创建——重用连接对象是坏主意,因为错误处理变得非常痛苦。也没有必要;连接是池化的,并且连接对象只是物理连接的临时句柄,因此在每个需要一个连接的方法中创建一个单独的连接(并处置它)是完全可以的(当然,如果你不这样做,你可以使用辅助方法/工厂想要共享连接字符串或进行其他设置)。 如果您想以随机访问方式测试数据读取器的结果,请创建DataTable 并调用其Load 方法,传递您的数据读取器。这将用数据填充DataTable,然后你可以用它做任何你想做的事情。 没有IF,这很糟糕。很坏。它违背了 ConnectionPool 的设计和功能。这不仅仅是违反设计:正如您所注意到的,不同的程序可能同时使用同一个对象,而您正在经历的后果;这对性能也非常不利。根据使用的提供程序,您可以在相同的网络条件下执行相同的查询,在几十秒而不是几毫秒内完成。 UI 中的数据绑定就是其中一种情况。 【参考方案1】:

您正在使用Public 连接对象,因为 cmets 状态不是要走的路。但最重要的是,请注意,只有一个 SqlDataReader 可以与一个 SqlConnection 关联,这加剧了单个共享连接的问题。

SqlDataReader.Read Method

每个关联的 SqlConnection 一次只能打开一个 SqlDataReader,任何打开另一个的尝试都将失败,直到第一个被关闭。同样,在使用 SqlDataReader 时,关联的 SqlConnection 会忙于为其提供服务,直到您调用 Close。

您可能已经有一个打开的阅读器,这就是为什么您会看到另一个数据集的结果。

【讨论】:

我不认为我有一个开放的阅读器连接 - 在我试图确保我不泄漏内存的痴迷中,我确实确保每个人都调用 close() 和 dispose()使用后,当我看到它正在阅读发票表时,我确实仔细检查了那部分代码。但我将删除公共连接并将其更改为在每个子中根据需要打开和关闭,希望这样可以解决问题。【参考方案2】:

正如@jmcilhenny、@Jeroen Mostert 和@Jimi 在 cmets 中所述,其根本原因是使用单个公共数据库连接。我现在更改了代码,以便每次我需要使用专用连接访问数据库时,它都会连接和断开数据库,现在它可以正常工作了。

【讨论】:

以上是关于“当不存在数据时尝试读取无效。”,但“hasrows”为真的主要内容,如果未能解决你的问题,请参考以下文章

尝试解析 json 字符串,但得到对象“”的预期开始,但改为“EOF”

ValueError: 提供 'c' kwarg 或 'color' kwarg 但不能同时提供;它们不同,但它们的功能重叠

文件存在但 java file.exists() 但返回 false

Node JS 正在运行但没有响应。工作,但随后定期停止响应

我正在尝试从邮递员发送帖子请求,但起初请求被接受,但数据存储为空

Angular 2 FormControl.reset() 不起作用,但 .resetForm() 起作用(但打字稿错误)