问题标签 [tdataset]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
15202 浏览

delphi - Delphi:在 OnBeforePost 事件中取消 TDataSet.Post

在我们的主数据输入屏幕上,我们在 OnBeforePost 事件中有一个确定/取消对话框。

  • 好的,让事情顺其自然
  • 立即取消Dataset.Cancel;

它完成了它的意图,回滚任何更改并将数据集置于浏览模式。

这对大多数客户来说都很好,但我们被问到是否可以将其更改为

  • Cancel,Abort the Post 并保持在编辑模式,并保留当前的更改。

如果他们想取消,可以使用取消按钮。

查看源代码procedure TDataSet.Post;似乎不可能以这种方式使用该事件。

有人对可以做到这一点的方式有任何想法吗?

跟进:这就是我现在选择的处理方式

0 投票
3 回答
3504 浏览

delphi - 根据过滤器字符串检查 TDataSet 行

我在内存 TDataSet 后代中使用DevExpress TdxMemData 。虽然它具有 Filtered: Boolean 和 Filter: String 属性,但实际上并没有自动对它们执行任何操作,而是依赖于 OnFilterRecord 事件的 Accept 参数的结果。

所以我正在寻找的是一种解析过滤器文本并将其应用于数据集的方法(可能在 TdxMemData 或 DevExpress 代码套件中的其他地方)。

理想情况下,我想要一种针对过滤器测试单个行的方法,以查看它是否匹配而不将其从数据集中过滤出来(我想突出显示与过滤器匹配的行)。

示例过滤器字符串:

所以有嵌套的and's and or's。它实际上是由 DevExpress TcxDBFilterControl 构建的。

我真的希望我缺少一些简单的东西。

更新:我向DevExpress 开了一张票,看看他们是否支持任何类型的解决方案。我确实找到了他们不支持在 TdxMemData 上过滤的答案。

0 投票
4 回答
1145 浏览

delphi - 如何将 TField 声明为可为空?

我正在设置一个基于 ADO 的客户端数据集,当我尝试将空值插入 TIntegerField 时,在发布时我得到Project raised exception class EDatabaseError with message 'Non-nullable column cannot be updated to Null'.

我知道我以前见过一种将 TField 设置为可为空的方法,但我不记得在哪里或如何。有谁知道如何解决这一问题?

编辑:该字段在设计时设置为Required = false,我已经验证它在运行时仍然是错误的,但我仍然得到错误。

0 投票
3 回答
6193 浏览

delphi - 在 DBGrid 中移动列似乎会移动附加的数据集字段

上周我观察到了一些我没有预料到的事情,将在下面描述。我很好奇为什么会发生这种情况。它是 TDataSet 类内部的东西、TDBGrid 的工件还是其他东西?

打开的 ClientDataSet 中的字段顺序发生了变化。具体来说,我在使用 FieldDefs 定义其结构后,通过调用 CreateDatatSet 在代码中创建了一个 ClientDataSet。此 ClientDataSet 结构中的第一个字段是名为 StartOfWeek 的日期字段。不久之后,我也编写的代码(假设 StartOfWeek 字段位于第零位 ClientDataSet.Fields[0])失败了,因为 StartOfWeek 字段不再是 ClientDataSet 中的第一个字段。

经过一番调查,我了解到 ClientDataSet 中的每个字段都可能在特定时刻出现在与创建 ClientDataSet 时的原始结构不同的某个位置。我不知道这可能会发生,在谷歌上搜索也没有提到这种效果。

发生的事情不是魔术。这些字段本身并没有改变位置,也没有根据我在代码中所做的任何事情而改变。导致字段在 ClientDataSet 中物理出现位置变化的原因是用户更改了 ClientDataSet 附加到的 DbGrid 中列的顺序(当然是通过 DataSource 组件)。我在 Delphi 7、Delphi 2007 和 Delphi 2010 中复制了这种效果。

我创建了一个非常简单的 Delphi 应用程序来演示这种效果。它由一个带有一个 DBGrid、一个 DataSource、两个 ClientDataSet 和两个 Button 的表单组成。此表单的 OnCreate 事件处理程序如下所示

Button1(标记为 Show ClientDataSet Structure)包含以下 OnClick 事件处理程序。

要演示移动场效果,请运行此应用程序并单击标有 Show ClientDataSet Structure 的按钮。您应该会看到类似此处所示的内容:

接下来,拖动 DBGrid 的列来重新排列字段的显示顺序。再次单击 Show ClientDataSet Structure 按钮。这次您将看到与此处显示的内容类似的内容:

此示例的显着之处在于 DBGrid 的列正在移动,但对 ClientDataSet 中 Fields 的位置有明显影响,因此 ClientDataSet.Field[0] 中的字段位置为 1点不一定在片刻之后。而且,不幸的是,这显然不是 ClientDataSet 问题。我对基于 BDE 的 TTables 和基于 ADO 的 AdoTables 进行了相同的测试,得到了相同的效果。

如果您从不需要引用在 DBGrid 中显示的 ClientDataSet 中的字段,那么您不必担心这种影响。对于你们其他人,我可以想到几个解决方案。

避免此问题的最简单但不必要的优选方法是防止用户重新排序 DBGrid 中的字段。这可以通过从 DBGrid 的 Options 属性中删除 dgResizeColumn 标志来完成。虽然这种方法是有效的,但从用户的角度来看,它消除了潜在的有价值的显示选项。此外,删除此标志不仅会限制列重新排序,还会阻止调整列大小。(要了解如何在不删除列调整大小选项的情况下限制列重新排序,请参阅http://delphi.about.com/od/adptips2005/a/bltip0105_2.htm。)

第二种解决方法是避免根据字面位置引用数据集的字段(因为这是问题的本质)。换句话说,如果您需要引用 Count 字段,请不要使用 DataSet.Fields[2]。只要您知道字段的名称,就可以使用 DataSet.FieldByName('Count') 之类的名称。

然而,使用 FieldByName 有一个相当大的缺点。具体来说,此方法通过遍历 DataSet 的 Fields 属性来识别字段,并根据字段名称查找匹配项。由于每次调用 FieldByName 时都会执行此操作,因此在需要多次引用字段的情况下(例如在导航大型 DataSet 的循环中)应避免使用此方法。

如果您确实需要重复(并且多次)引用该字段,请考虑使用类似于以下代码片段的内容:

还有第三种解决方案,但这仅在您的 DataSet 是 ClientDataSet 时可用,就像我原来的示例中的那个一样。在这些情况下,您可以创建原始 ClientDataSet 的克隆,它将具有原始结构。因此,无论用户对显示 ClientDataSets 数据的 DBGrid 做了什么,在第零位置创建的任何字段仍将位于该位置。

这在以下代码中进行了演示,该代码与标记为 Show Cloned ClientDataSet Structure 的按钮的 OnClick 事件处理程序相关联。

如果您运行此项目并单击标有“显示克隆的 ClientDataSet 结构”的按钮,您将始终获得 ClientDataSet 的真实结构,如下所示

附录:

需要注意的是,基础数据的实际结构不受影响。具体来说,如果在更改 DBGrid 中列的顺序后,调用 ClientDataSet 的 SaveToFile 方法,则保存的结构是原始(真正的内部)结构。此外,如果将一个 ClientDataSet 的 Data 属性复制到另一个,则目标 ClientDataSet 也会显示真实的结构(这类似于克隆源 ClientDataSet 时观察到的效果)。

同样,对绑定到其他测试数据集(包括 TTable 和 AdoTable)的 DBGrid 的列顺序的更改实际上不会影响基础表的结构。例如,显示来自 Delphi 附带的 customer.db 示例 Paradox 表的数据的 TTable 实际上并没有改变该表的结构(您也不希望它改变)。

我们可以从这些观察中得出结论,DataSet 本身的内部结构保持不变。因此,我必须假设在某处存在 DataSet 结构的二级表示。而且,它必须与 DataSet 相关联(这似乎有点过头了,因为并非所有使用 DataSet 都需要这个),与 DBGrid 相关联(这更有意义,因为 DBGrid 正在使用此功能,但不是由 TField 重新排序似乎与 DataSet 本身持​​续存在的观察结果支持),或者是其他东西。

另一种选择是效果与 TGridDataLink 相关联,TGridDataLink 是为多行感知控件(如 DBGrids)提供数据感知的类。但是,我也倾向于拒绝这种解释,因为这个类与网格相关联,而不是与 DataSet 相关联,因为效果似乎与 DataSet 类本身有关。

这让我回到了最初的问题。这种效果是 TDataSet 类内部的东西、TDBGrid 的工件还是其他东西?

请允许我在这里强调一些我添加到以下评论之一的内容。最重要的是,我的帖子旨在让开发人员意识到,当他们使用可以更改列顺序的 DBGrid 时,他们的 TField 的顺序也可能会发生变化。该工件可能会引入难以识别和修复的间歇性和严重错误。而且,不,我不认为这是一个 Delphi 错误。我怀疑一切都按照设计的方式工作。只是我们中的许多人都不知道这种行为正在发生。现在我们知道了。

0 投票
3 回答
1745 浏览

delphi - 如果 FIndKey 结果为 False,则不返回任何记录?

使用 TDataSet.FindKey 您可以定位记录。当结果为 True 时,数据集光标将定位在找到的记录上。当结果为 False 时,光标不会移动。这会导致在发出 FindKey 之前的记录数据显示在数据感知组件中。

如何对 FindKey 的结果进行编码以返回空记录?

更新:(在选择正确答案之前等待了几天,因为我认为这是习惯,并且不想阻止进一步的反馈。)尽管我相信正确的答案来自 Marcelo,但有一些关于解决这种情况的建议,因为它是不可能有游标不在记录上。提出了几种解决方法。我选择了我自己的一个。它是这样的:

我所做的是创建一个虚拟的空白记录,其中包含实际数据永远不可能的索引,即:第一个索引值永远不会是-1。如果初始搜索为空,则 FindKey 会将光标定位在此空记录上。这将提供我所追求的视觉效果。

0 投票
2 回答
1384 浏览

database - 使用 MVC 范式的数据库应用程序

在经典的 Delphi 数据库应用程序中,我们有一个表单,一组通过 TDataSources 连接到 TDataSets 的数据感知可视控件。如果想使用 MVC 模型设计数据库应用程序,TDataSet 组件应该放在哪里?他们是否应该保持状态并因此成为 View 的一部分?还是应该将它们封装在某个模型对象中?如果是后者,它们如何绑定到视觉组件?

0 投票
1 回答
2955 浏览

database - 在 TDataset Delphi 中交换两条记录的最佳方法?

对 delphi 和数据库编程一般来说是新手,但我很好奇是否有更好的方法来交换 TDataset 中的记录?我已经阅读了一些帮助,但找不到任何明显的方法。目前,我实施了一个程序来将记录向下移动到数据集,直到它们到达 Eof 标记。但是,当我到达数据中的最后一条记录时,我遇到了一些奇怪的错误。我所拥有的只是实现了一个标准的数组式交换例程,试图在处理活动记录时保留数据和诸如此类的东西。

到目前为止的代码

0 投票
4 回答
500 浏览

delphi - 在设计时将 TDataSet 嵌入到表单中

我正在寻找一种方法来为 delphi 中的 TDBLookupComboBox 提供 ListSource,而无需在数据库服务器上使用实际表来绘制该列表。Combo Box 的 DataField 是 1 个字符的字段,其中包含一个编码值,例如 'A' = 'Drivers License'、'B' = 'Passport'、'C' = 'Library Card' 等。也就是说该表仅包含 A、B 或 C。应用程序负责在 GUI 中显示“驾驶执照”。通常一个数据库可能有一个查找表,但这个数据库没有,我不能添加一个。我的想法是 DB 查找控件的 DataSource 和 ListSource 不必是同一个数据库,所以如果可以在我的表单中定义一个包含查找数据的小表,那么我可以使用它不需要真正的数据库表。

有谁知道允许在表单上定义 TDataSet 而没有任何实际数据文件的 delphi 组件?

0 投票
4 回答
4260 浏览

delphi - Delphi,TcxGrid或TDataSet中最快的记录访问方法是什么

我正在使用 Delphi 2007 和 TcxGrid 来显示文件库的内容。该数据库包含有关文件类型、名称、路径和扩展名的信息。

在测试中,我通过 TDataSet 将 1700 条记录加载到网格中。我还在网格中为另外 3 个需要计算的字段腾出空间。它们是文件是否存在、文件大小和修改日期。

我的目标是向用户显示所有存储的信息(效果很好而且速度很快),然后在后台线程中找到其他三个数据字段的信息,然后将它们插入 TcxGrid。这个问题与我正在做的线程几乎没有关系。它工作正常。

我的问题是访问已经构建的网格中的字段在我访问它时会大大减慢。我尝试了两种不同的方法...

  1. Grid.DataController.Values[RecordIndex,FieldIndex] - 但这是一个变体,我怀疑这就是它如此缓慢的原因

  2. Grid.DataController.DataSet.FindFirst Grid.DataController.DataSet.FindNext Grid.DataController.DataSet.Fields[FieldIndex] 但是使用这种“seek”方法和我尝试的第一种方法一样慢。定位和移动也很慢。

这么长的问题,什么是访问记录的最快方法?

0 投票
2 回答
1524 浏览

delphi - 如何确定一条记录何时插入 TDataSet?

我正在编写一个网格控件,它将显示 TDataSet 或 TObjectList 的内容。当你只需要支持 TDataSet 时,事情就很简单了:

  1. 通过 TDataLink 后代链接到数据集。
  2. 在绘制网格的内容时,您可以使用缓冲在该 TDataLink 中的记录来绘制您需要的内容。
  3. 不需要在某处有单独的对象来表示 TDataSet 中的行,因为您总是只在缓冲区中绘制行。

在我的例子中,我还需要接受来自其他几个来源的数据,这意味着我需要一个代表每一行的对象(也因为控件需要相当多的行状态)。

但这会导致上述模型出现问题。因为我有一个代表每一行的对象,所以需要在从 TDataSet 添加或删除记录时通知我。我只是看不出该怎么做。

显然,我不想挂在数据集事件上;它们可能已经在使用中,并且 TDataLink 旨在成为我的控件和数据集之间的中介。我尝试使用 DataEvent 虚拟方法失败了,因为它根本不会告诉您是否正在添加/删除记录。

有任何想法吗?