【问题标题】:How can I delete records in a loop?如何在循环中删除记录?
【发布时间】:2016-11-29 23:43:24
【问题描述】:

我正在编写一个业务服务,它需要迭代 BC 中的所有记录,并删除其中一些:

bc.ExecuteQuery(ForwardBackward);
var isRecord = bc.FirstRecord();
while (isRecord) {
  if (...) {
    bc.DeleteRecord();
  }
  isRecord = bc.NextRecord();
}

但是,DeleteRecord moves the cursor to the next one,所以我会为每个被删除的记录跳过一条记录,这不是我想要的。是否有任何标准的ish 方法来解决这个问题?

我想我可以只做两个循环,一个用于检查,另一个用于删除......它会起作用,但是对记录进行两次迭代感觉很愚蠢,必须有比这更好的方法:

bc.ExecuteQuery(ForwardBackward);
var isRecord = bc.FirstRecord();
var list = [];
while (isRecord) {
  if (...) {
    list.push(bc.GetFieldValue("Id"));
  }
  isRecord = bc.NextRecord();
}

bc.ClearToQuery();
bc.SetSearchSpec("Id", "='" + list.join("' OR ='") + "'");  // "='1-ABCD' OR ='1-1234'"
bc.ExecuteQuery(ForwardBackward);
while (bc.FirstRecord()) {
  bc.DeleteRecord();
}

【问题讨论】:

  • 问题是 DeleteRecord 没有返回任何东西。否则,可以使用 if 循环轻松地重新安排逻辑。您推送到列表并有选择地删除的逻辑看起来已优化。

标签: siebel


【解决方案1】:

既然你在做ForwardBackward,你可以在删除后添加一个PreviousRecord调用:

bc.ExecuteQuery(ForwardBackward);
var isRecord = bc.FirstRecord();
while (isRecord) {
  if (...) {
    bc.DeleteRecord();
    bc.PreviousRecord();
  }
  isRecord = bc.NextRecord();
}

或者简单地向后循环:

bc.ExecuteQuery(ForwardBackward);
var isRecord = bc.LastRecord();
while (isRecord) {
  if (...) {
    bc.DeleteRecord();
  }
  isRecord = bc.PreviousRecord();
}

【讨论】:

  • 第二个肯定更好看。但是,两者都有一个问题:“如果对最后一条记录使用 DeleteRecord 方法,则光标指向任何内容”。不知道我是否可以从那里做一个 PreviousRecord。
  • @AJPerez 第一个不会有问题,因为即使PreviousRecord 不起作用,NextRecord 也会返回 falsy,我想。但是,是的,siebel BC 肯定会受益于 DeleteRecord() 返回某些东西,或者拥有 GetCurrent() 方法或其他东西
  • 我认为你可能是对的,所以我刚刚尝试了它们......但是发生了一些奇怪的事情:D。例如,如果我在 BC 中有 4 条记录并执行第二个代码(没有任何 if),它会删除第 4 条,跳过 3 条,并删除 2 和 1。当我刚刚删除最后一条记录时调用 Previous 不会似乎工作得太好了。第一个代码也跳过了其中一个元素,尽管在这种情况下我没有检查哪个元素或它何时被跳过。
  • @AJPerez 这确实很奇怪......我很抱歉,但我没有准备好测试任何这些的环境,我只是从头开始写。 “从逻辑上讲”,它应该可以工作,但 siebel 有时是一只奇怪的野兽 :-)
【解决方案2】:

将第一条记录的值存储在 var 中,然后在循环中检查记录是否存在。我建议你向前和向后尝试。 var 的值是递增的,因此,在 while 循环内放置一个元素命令,因此 var 现在将存储前一个元素。执行循环后。您可以轻松地递增到下一个元素。

【讨论】:

  • 请提供一些例子
【解决方案3】:

解决方案将直接取决于您的 if (...) 条件:

  • 如果是简单条件,可以转换为搜索 表达式,那么您只需简单地进行查询并删除 找到的所有东西。

  • 如果它是一个复杂的条件,不能作为搜索规范实现,那么您可以通过两种方式来实现(两者都有自己的缺点): a) 使用 DeleteRecord 和 PreviousRecord 的尴尬组合。 b)创建第二个方法,该方法将删除单个记录并为满足条件的每个记录调用它,类似这样

    function deleteRecord(sId:chars) {
      ...
      bc.SetSearchSpec("Id", sId);
      bc.ExecuteQuery(ForwardOnly);
      if (bc.FirstRecord()) {
        bc.DeleteRecord();
      }
    }
    ... 
    bc.ExecuteQuery(ForwardBackward);
    var isRecord = bc.FirstRecord();
    while (isRecord) {
      if (...) {
        deleteRecord(bc.GetFieldValue("Id"));
      }
      isRecord = bc.NextRecord();
    }
    ...
    

您的解决方案可以和选项 c),但是当 Id 列表太大时它将不起作用,因为这样的查询会导致巨大的 SQL 语句并且数据库对 SQL 查询大小有一些限制(而 DBA 不会很高兴在日志中看到此类查询)。

我更喜欢选项 b)。您可以通过在主函数中创建相同 BC 的第二个实例并通过引用 deleteRecord 函数来对其进行优化。

【讨论】:

  • 在这个特定的场景中,条件非常简单,我将其移至搜索规范,并带有“while FirstRecord, DeleteRecord”。我更感兴趣的是了解其他人在复杂案例中是如何做到的。我想我也更喜欢你的 b) 选项,它更干净。
猜你喜欢
  • 2022-01-09
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多