我无法在任何地方找到答案。使用Delphi XE7和TClientDataSet,DataSnap& SQL Server。我需要插入一条记录,应用更新,然后刷新该记录,以便我可以获取Id并将其分配给我的对象。似乎是相当基本的要求,但恰恰相反,它被证明是一种皇室般的痛苦。
我在EDN上找到了明显的东西,SO和Bob博士:
http://edn.embarcadero.com/article/20847
DataSnap and the autoinc field
http://www.drbob42.com/examines/examinC0.htm
然而,这些似乎专注于TClientDataSet的“刷新”以重新获取整个表/查询。虽然这确实解决了Id字段本身(好!),但它也将光标移出刚插入的当前记录,因此我无法获取Id并将其分配给我的对象。另外,对于基于HTTP的性能,我不想在每次插入记录时都重新获取整个表,如果有10,000条记录,这将消耗太多带宽并且速度非常慢!
请考虑以下代码:
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;
有谁知道如何实现这一目标?我需要能够刷新并保持当前记录,否则我不知道刚刚创建的记录的ID,并且GUI无法专注于当前记录。
希望显而易见的是我错过了。
干杯。 瑞克。
答案 0 :(得分:2)
假设您可以在DataProvider的AfterUpdateRecord
事件中获取新ID,那么您的事件处理程序可能如下所示(DeltaDS的当前记录是刚刚插入到SourceDS中的记录):
if (UpdateKind = ukInsert) then begin
DeltaDS.FindField('Id').NewValue := <TheNewID>;
end;
确保在提供程序中设置了poPropogateChanges
选项。这会将已更改的 Id 字段传回ClientDataSet。
现在你可以摆脱FDataSet.Refresh
电话。
答案 1 :(得分:1)
SQL Server允许您以多种方式获取它生成的最后一个身份 - 不需要&#34;刷新&#34;记录/查询意味着重新发出SELECT并且可以产生不可容忍的副作用。您可以使用SELECT SCOPE_IDENTITY()或使用OUTPUT子句。如果Delphi数据库驱动程序支持它,TField.AutogenerateValue应自动完成该任务(参见http://docwiki.embarcadero.com/Libraries/XE7/en/Data.DB.TField.AutoGenerateValue)
否则你必须将新数据放入delta(请参阅Raabe回答 - 这必须在读取数据库的数据库服务器上完成),然后将其发送回客户端。您还需要正确设置TField.ProviderFlags以确保正确应用数据(请参阅http://docwiki.embarcadero.com/RADStudio/XE7/en/Influencing_How_Updates_Are_Applied),通常您不希望这些字段出现在更新中。