Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 仅在插入后使用AutoInc键和刷新当前记录进行数据捕捉_Delphi_Auto Increment_Datasnap - Fatal编程技术网

Delphi 仅在插入后使用AutoInc键和刷新当前记录进行数据捕捉

Delphi 仅在插入后使用AutoInc键和刷新当前记录进行数据捕捉,delphi,auto-increment,datasnap,Delphi,Auto Increment,Datasnap,我在任何地方都找不到这个问题的答案。将Delphi XE7与TClientDataSet、DataSnap和SQL Server一起使用。我需要插入一条记录,应用更新,然后刷新该记录,以便获取Id并将其分配给我的对象。这似乎是一个相当基本的要求,但恰恰相反,它被证明是一个皇家的痛苦 我在EDN上找到了明显的东西,所以Bob博士: 然而,这些似乎集中在TClientDataSet的“刷新”上,以重新获取整个表/查询。虽然这确实解决了Id字段本身(很好!),但它也将光标从刚刚插入的当前记录上移

我在任何地方都找不到这个问题的答案。将Delphi XE7与TClientDataSet、DataSnap和SQL Server一起使用。我需要插入一条记录,应用更新,然后刷新该记录,以便获取Id并将其分配给我的对象。这似乎是一个相当基本的要求,但恰恰相反,它被证明是一个皇家的痛苦

我在EDN上找到了明显的东西,所以Bob博士:

然而,这些似乎集中在TClientDataSet的“刷新”上,以重新获取整个表/查询。虽然这确实解决了Id字段本身(很好!),但它也将光标从刚刚插入的当前记录上移开,因此我无法获取Id并将其分配给我的对象。另外,对于HTTP的性能,我真的不想每次插入一条记录时都重新蚀刻整个表,如果有10000条记录,这将消耗太多的带宽,速度会慢得可笑

考虑以下代码:

function TRepository<I>.Insert(const AEntity: I): I;
begin
  FDataSet.DisableControls;
  try
    FDataSet.Insert;
    AssignEntityToDataSet(AEntity);  // SET'S ALL THE RELEVANT FIELDS
    FDataSet.Post;
    FDataSet.ApplyUpdates(-1);
    FDataSet.Refresh;  // <--- I tried RefreshRecord here but it cannot resolve the record
    AEntity.Id := FDataSet.FieldByName('Id').AsInteger; // <----- THIS NOW POINTS TO WRONG ROW
  finally
    FDataSet.EnableControls;
  end;
end;
function TRepository.Insert(常数:I):I;
开始
FDataSet.DisableControls;
尝试
FDataSet.Insert;
AssignEntityToDataSet(实体);//设置所有相关字段
FDataSet.Post;
FDataSet.applyUpdate(-1);

FDataSet.Refresh;// 假设您可以在数据提供程序的
AfterUpdateRecord
事件中获得新ID,那么您的事件处理程序可能如下所示(DeltaDS的当前记录就是刚刚插入到SourceDS中的记录):

if(UpdateKind=ukInsert)然后开始
DeltaDS.FindField('Id')。NewValue:=;
结束;
确保在提供程序中设置了
poPropogateChanges
选项。这将把更改的Id字段传输回ClientDataSet


现在,您可以摆脱FDataSet.Refresh调用。

SQL Server确实允许您以多种方式获取它生成的最后一个标识—无需“刷新”记录/查询,这意味着重新发出SELECT,并可能产生不可忽视的副作用。您可以使用SELECT SCOPE_IDENTITY()或使用OUTPUT子句。如果Delphi数据库驱动程序支持它,则TField.AutogenerateValue应该自动完成该任务(请参阅)


否则,您必须在读取新数据后将其放入增量(请参阅Raabe答案-这必须在实际与数据库对话的datasnap服务器上完成),以便将其发送回客户端。您还需要正确设置和TField.ProviderFlags以确保数据正确应用(请参阅),通常您不希望这些字段出现在更新中。

我曾在DataSetProvider.AfterApplyUpdate中提供此信息。在该事件中,您可以将其分配给OwnerData参数,然后在调用ApplyUpdate后重新读取它。这是假设您能够在该点检索信息。我曾经将ID作为Insert SQL语句的一部分返回。假设客户端上发生此事件:ClientDataSetafterApplyUpdate(发件人:ToObject;var OwnerData:OleVariant),我将如何从中获取该数据?我想我需要从DataSnap服务器返回一些东西?不知道怎么做?好的,所以我想出了如何从Provider.afterapplyUpdate返回一些用户自己的数据。但是,当该事件触发时,我无法访问我的对象。有什么建议吗?谢谢你。我可以从DeltaDS获取返回给客户机的NewValue,但是我找不到在插入之后获取新Id的方法?我正在使用连接到TFDQuery组件的MSSQL,但是它似乎没有填充TFDAutoIncField。我假设它对新记录使用某种自动生成的SQL INSERT语句。例如,当使用TFDUpdateSQL组件时,它似乎在INSERT语句之后立即执行“SELECT SCOPE_IDENTITY()as Id,*”,但我不知道如何获取该标识值。关于如何获取此值有何想法?在进一步测试之后,无法在AfterUpdateRecord事件期间获取行的作用域_IDENTITY(),因为直到TDataSetProvider.InternalApplyUpdate方法结束时,插入事务才不在作用域之外,“如果FTTransaction启动,则(数据集作为IProviderSupporting).PSEndTransaction(提交)”被执行。因此,我需要找到另一种方法来实现这一点,可能是在AfterApplyUpdate中,但这只允许我访问OwnerData变量,而不是DeltaDS。事实证明,这既棘手又耗时。您是否尝试过在DataSetProvider中设置ResolveToDataSet?这应该让FDQuery完成插入任务,因此应该更新FDQuery的autoinc字段。但是,我随后将TFDAutoIncField更改为TIntegerField,并将AutogenerateValue设置为AutoInc,这将填充SourceDS,然后将其分配给DeltaDS。因此,它终于起作用了。非常感谢你的帮助。谢谢。我知道如何获取最后更新的Id,但是insert语句似乎是由TFDQuery组件在内部处理的。我也尝试过按建议使用TFDAutoIncField,但也无法实现。我觉得我很接近,但我错过了一些东西。由于缺乏良好的文档和工作示例,这确实非常令人沮丧。还有其他想法吗?通常在使用Datasnap时,我发现数据库访问的“自动”管理不够灵活,我更喜欢在提供者事件中处理它。这意味着要编写更多的代码,但我完全可以控制将哪些查询发送到数据库,我可以处理结果并将适当的数据发送回客户端数据集。谢谢您的帮助。Uwe与您关于AutoInc字段的建议相结合解决了这个问题。您能否分享一些示例,说明如何处理提供者事件中的删除/更新?我现在正努力让更复杂的查询正常工作。似乎在启用ResolveToDataSet的情况下,更新/删除方法不起作用
  if (UpdateKind = ukInsert) then begin
    DeltaDS.FindField('Id').NewValue := <TheNewID>;
  end;