简体   繁体   English

TUniQuery (UniDac TUniQuery) Last 和 First 方法是直接跳转还是逐条记录滚动

[英]Does TUniQuery (UniDac TUniQuery) Last and First methods jump directly or do a record by record scroll

I have a program that must set up a more less complex screen after the user goes to a certain record in a dataset (TUniQuery).我有一个程序必须在用户转到数据集中的某个记录(TUniQuery)后设置一个更简单的屏幕。 The user can jump on many ways: a combobox, search box and finally a DbNavigator.用户可以通过多种方式跳转:combobox、搜索框,最后是 DbNavigator。 Going from the first to the last record takes forever.从第一个记录到最后一个记录需要很长时间。 After following program execution I discovered that pressing the last button on the DBNavigator causes each record on the dataset to be visited, and so, on each one, the screen is uselessly built.在执行程序之后,我发现按下 DBNavigator 上的最后一个按钮会导致数据集上的每条记录都被访问,因此,在每条记录上,屏幕都是无用的。 Same from any record going to the first or last.从任何记录到第一个或最后一个记录都是一样的。 It was my understanding, that such methods ( First and Last ) will do a direct jump.我的理解是,这样的方法( FirstLast )会直接跳转。 Maybe is a particular behavior on the Unidac components, but I can´t find any reference nor property to modify it.也许是 Unidac 组件上的一种特殊行为,但我找不到任何参考或属性来修改它。 Currently, I´m planning to set a flag on the BeforeScroll event, but since AfterScroll also happens after each one, I can´t learn when the dataset has ended scrolling.目前,我计划在BeforeScroll事件上设置一个标志,但由于AfterScroll也发生在每个事件之后,我无法知道数据集何时结束滚动。 I can´t neither find any reference on Delphi documentation that simply states我在 Delphi 文档中也找不到任何简单说明的参考
Call Last to make the last record in the dataset active调用 Last 以激活数据集中的最后一条记录

Following the source code I found this:按照源代码,我发现了这个:
Short answer : Yes, a TDataset jumps directly to the first and last records when possible but...简短回答:是的,TDataset 尽可能直接跳转到第一条和最后一条记录,但是......

Long answer : Delphi has internal data events ( DB unit, TDataEvent ) that are broadcasted so data aware controls can update properly.长答案:Delphi 具有广播的内部数据事件( DB单元, TDataEvent ),因此数据感知控件可以正确更新。 Methods like Next , Prior and many others use function MoveBy , which generates a Before/AfterScroll events and also internal events. NextPrior和许多其他方法使用 function MoveBy ,它生成一个Before/AfterScroll事件和内部事件。 MoveBy may fetch some extra rows if needed.如果需要, MoveBy可能会获取一些额外的行。 Let's say you have twenty rows fetched from a thirty rows dataset.假设您从 30 行数据集中提取了 20 行。 Your current record is fifteen.你目前的记录是十五。 You call MoveBy(2) .你打电话给MoveBy(2) As expected, your new record is seventeen.不出所料,你的新纪录是十七岁。 In this case the following occurs:在这种情况下,会发生以下情况:

  1. BeforeScroll滚动前
  2. ActiveRecord is incremented twice (in a loop) but no rows are fetched ActiveRecord 递增两次(在循环中),但未获取任何行
  3. internal DataEvent: deDataSetScroll内部数据事件:deDataSetScroll
  4. AfterScroll后滚动

Note that no program events occur while scrolling.请注意,滚动时不会发生任何程序事件。 BeforeScroll occurs on record fifteen and AfterScroll on seventeen. BeforeScroll出现在记录十五和AfterScroll在十七。

Now, same scenario, but this time MoveBy(10) is called.现在,同样的场景,但这次调用了MoveBy(10) Five rows are already fetched (20 - 15) and five more need to be retrieved.已经提取了五行(20 - 15),还需要检索另外五行。 In this case the sequence is:在这种情况下,顺序是:

  1. BeforeScroll滚动前
  2. ActiveRecord is incremented by five (in a loop) but no rows are fetched ActiveRecord 递增 5(在循环中),但未获取任何行
  3. Active record is incremented by five, in the same loop.在同一个循环中,活动记录增加 5。 On each cycle, a record is fetched (no program events occur)在每个循环中,获取一条记录(不发生程序事件)
  4. internal DataEvent: deDataSetChange内部数据事件:deDataSetChange
  5. AfterScroll后滚动

Every thing runs fine.每件事都运行良好。 The problem raises with the Last method that does not use MoveBy and assumes that records were always fetched:不使用MoveBy并假定始终获取记录的Last方法会出现问题:

procedure TDataSet.Last;  
begin  
  CheckBiDirectional;  
  CheckBrowseMode;  
  DoBeforeScroll;  
  ClearBuffers;  
  try
    InternalLast;  
    GetPriorRecord;  
    GetPriorRecords;  
  finally  
    FEOF := True;  
    DataEvent(deDataSetChange, 0);  // Problem! Causes TJvDBSearchComboBox to retrieve all records (again)
    DoAfterScroll;  
  end;  
end;  

As you can see, Last method always broadcast a deDataSetChange event even when all records have been fetched .如您所见,即使所有记录都已获取, Last方法也始终广播deDataSetChange事件 In my particular case of four records, the user presses the last button of a TDBNavigator which in turn calls Last method.在我的四个记录的特殊情况下,用户按下TDBNavigator的最后一个按钮,该按钮又调用Last方法。 The event deDataSetChange is broadcasted, and then a TJvDBSearchComboBox (from JVCL library) reacts to this event by visiting each row with a "while not eof...next" loop to update its contents, and generating Before/AfterScroll events.广播deDataSetChange事件,然后TJvDBSearchComboBox (来自 JVCL 库)通过使用“while not eof...next”循环访问每一行来更新其内容并生成Before/AfterScroll事件来对此事件做出反应。

I love Delphi, but is one of the things I don´t like about datasets.我喜欢 Delphi,但这是我不喜欢数据集的原因之一。 There is no way for a program to learn if certain data event was triggered due to a user action, or the program itself.程序无法了解是否由于用户操作或程序本身触发了某些数据事件。 I have suggested in Delphi presentations, for a way to travel through a dataset without events been triggered (as MoveBy does) and then, components like TJvDBSearchComboBox could use it, or at least a flag or the like in the dataset that could be turned on before starting to visit each record.我在 Delphi 演示文稿中提出了一种在不触发事件的情况下遍历数据集的方法(如MoveBy所做的那样),然后,像TJvDBSearchComboBox这样的组件可以使用它,或者至少可以打开数据集中的标志等在开始访问每条记录之前。 Also, Last should check if records were indeed retrieved.此外, Last应该检查是否确实检索到了记录。

Some will says that's easy to implement by myself, and it is indeed when your code scrolls through the dataset.有些人会说这很容易由我自己实现,而且确实是当您的代码滚动浏览数据集时。 But in the case of a TDBNavigator and TJvDBSearchComboBox I have no control over them.但在TDBNavigatorTJvDBSearchComboBox的情况下,我无法控制它们。 Some other will say don´t use JVCL, There's no easy answer here.其他人会说不要使用 JVCL,这里没有简单的答案。 Also, FYI, First method exhibits the same behaviour.此外,仅供参考,一种方法表现出相同的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM