我在表单上有一个FDQuery,以及根据其recordCount启用和禁用组件的操作(在> 0时启用)。
大多数时候,recordCount属性返回查询中的实际记录数。有时,recordcount返回负值,但我可以看到与查询关联的网格上的记录。
RecordCount返回的值介于-5和-1之间,直到现在。
我该如何解决这个问题?为什么它会返回负值?
答案 0 :(得分:1)
为什么会返回负值?
这不是特定于FireDAC的,这是提供TDataSet
接口的所有Delphi库的正常行为。
TDataSet.RecordCount
从未得到过保证。它甚至在文档中说。这是一个额外的功能。有时它可能会起作用,有时则不起作用。它只能对CSV,DBF,Paradox表和其他类似ISAM引擎等非SQL表数据可靠地工作。
我该如何解决这个问题?
在现代世界中依靠这一功能始终是一项冒险的尝试。 因此,您可以更好地设计程序,以便永远不会使用此功能,或仅在极少数特定情况下使用。 相反,你应该明白你的程序真正要求图书馆提出什么问题,然后找到一个"语言"通过调用其他功能来提出这个问题,更适合您的情况。
现在告诉我,当你在谷歌搜索时,你经常阅读第10页,最多第100页?几乎没有,对吗?您的程序用户也几乎永远不会向下滚动数据网格。记住这一点。 您始终需要向用户显示第一个数据并快速执行。但很少有最后的数据。
现在,有三个例子。
1)您从某些远程服务器读取数据,网络速度较慢。您每秒只能读取100行。你的网格有空间显示20个第一行。其余用户必须滚动。总的来说,查询可以为您过滤10 000行。
如果您只是向用户显示这20行 - 那么它几乎可以立即工作,从您开始读取数据到填充网格并将其呈现给用户只需0.2秒。只有当用户通过滚动请求时才会获取其余数据(为了清楚起见,我在这里稍微简化一下,我知道预缓存TDataset.Buffers
)。
因此,如果您调用RecordCount
函数,您的程序会执行什么操作?它会将所有记录下载到您计算的本地内存中。如此速度需要10 000/100 = 100秒,超过一分半钟
只需调用您调用RecordCount
过程的FetchAll
函数,就可以在0.2秒内但在1分40秒内对用户做出程序响应。
用户会非常紧张,等待完成。
2)想象一下,您正在从某些存储过程中获取数据。或者从表中,另一个应用程序插入行。换句话说,这不是一些静态只读数据,即在下载时生成的实时数据
那么,有多少行呢?例如,这一刻是1000行,在一秒钟内它将是1010行,在两秒钟内它可能是1050行,依此类推。
当这个值不时被改变时,One True Value是什么?
Oookey,你调用了RecordCount
函数,你SetLength
- 将你的数组编辑为1000,现在你从查询中读取了所有数据。但是下载数据需要一些时间。它通常很快,但它永远不会瞬间完成。因此,例如,您花了一秒钟将数据库查询数据的1000行下载到您的数组(或网格)中。但是当你这样做时,会生成/插入10行,而你的查询不是.EOF
,并且你继续获取行#1001,#1002,...#1010 - 然后你把它们放在数组中/ gris行只是不存在!
会不会好?
或者当你走出数组/网格边界时,你会取消查询吗? 这样你就不会有访问冲突 但相反,你会忽略并错过那些最近的10行。
这样好吗?
3)您的查询在调试时返回10 000行。您可以通过调用RecordCount
函数将它们全部下载到程序的本地内存中,它就像魅力一样,然后部署它。
您的客户端使用您的程序,数据会增长,有一天您的查询返回的不是10 000行,而是10 000 000。
您的程序调用{{1}}函数来下载所有这些行,它下载例如9 000 000百万...
....然后它因RecordCount
错误而崩溃。
根据其recordCount>启用和禁用组件0
这是获取您不需要的数据(确切数量的行)的错误方法,然后丢弃它。上面的例子向您展示了如何使您的程序变得脆弱和缓慢。
你真正想知道的是,是否有任何行或根本没有。 您无需计算广告了解其金额的所有行,您只想知道查询是否为空。
这正是您应该通过调用Out Of Memory
函数而不是TDataSet.IsEmpty
来提出的问题。