简体   繁体   English

Delphi TClientDataset SQL Server RowVersion

[英]Delphi TClientDataset SQL Server RowVersion

Does anyone have any experience using SQL Server 's RowVersion column with TClientDataset ? 有没有人有使用SQL Server的RowVersion列和TClientDataset Specifically, I need to get the RowVersion value back on insert. 具体来说,我需要在插入时重新获得RowVersion值。 It seems to get the RowVersion value back on updates but a newly inserted row it does not. 似乎在更新时重新获得了RowVersion值,但并没有获得新插入的行。

This seems to involve a similar problem to when you need to use a CDS with a SqlServer table which has an Identity field, where the value in the field is set by the server, so you don't know it during the CDS-side insert operation. 这似乎与需要将CDS与带有Identity字段的SqlServer表一起使用时的问题类似,该字段中的值由服务器设置,因此在CDS端插入期间您不知道它操作。 One way to do that is explained in this article http://edn.embarcadero.com/article/20847 . 本文http://edn.embarcadero.com/article/20847中介绍了一种实现此目的的方法。 It involves assigning a temporary, negative, value to the Identity field in the CDS in the OnNewRecord event, and then using the Refresh method of the CDS to retrieve the server-side identity field value once the new record has been posted to the server by calling ApplyUpdates . 它涉及在OnNewRecord事件中为CDS中的“标识”字段分配一个临时的负值,然后在新记录已通过以下方式发布到服务器后,使用CDS的Refresh方法检索服务器端标识字段的值。调用ApplyUpdates

In D7, which I'm using for this answer as a sort of lowest common denominator, this technique seems to work fine to a RowVersion field as well. 在D7中,我将此答案用作最低公分母,该技术似乎也适用于RowVersion字段。 An extract from a sample project is below. 下面是一个示例项目的摘录。 To get it working, I had to define the RowVersion field as an ftBytes field with a size of 8, and to change the ProviderFlags to exclude pfInWhere and pfInUpdate from the AdoQuery's identity field, ID. 为了使其正常工作,我必须将RowVersion字段定义为ftBytes字段,大小为8,并更改ProviderFlags以从AdoQuery的标识字段ID中排除pfInWherepfInUpdate

The RowVerStr field in the CDS is just to display the value legibly in a TDBGrid. CDS中的RowVerStr字段只是为了在TDBGrid中清晰显示该值。

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSetProvider1: TDataSetProvider;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    ADOQuery1ID: TAutoIncField;  //  The ID field is an Identity field on the server
    ADOQuery1IntValue: TIntegerField;  //  a user field
    CDS1: TClientDataSet;
    CDS1ID: TAutoIncField;
    CDS1IntValue: TIntegerField;
    CDS1RowVersion: TBytesField;
    CDS1RowVerStr: TStringField;  //  just for display, fkInternalCalc, size = 20
    ADOQuery1RowVersion: TBytesField;
    procedure FormCreate(Sender: TObject);
    procedure CDS1AfterPost(DataSet: TDataSet);
    procedure CDS1AfterDelete(DataSet: TDataSet);
    procedure CDS1NewRecord(DataSet: TDataSet);
    procedure CDS1AfterInsert(DataSet: TDataSet);
    procedure CDS1CalcFields(DataSet: TDataSet);
  public
    FID : Integer;  //  To generate temporary value for CDS identity field
    function NextID : Integer;
  end;

[...]

function GetRowVerString(V : Variant) : String;
var
  i,
  Dim,
  Min,
  Max : Integer;
  i64 : Int64;
begin
  Result := '';
  if not VarIsArray(V) then Exit;
  Dim := VarArrayDimCount(V);
  Max := VarArrayHighBound(V, Dim);
  Min := VarArrayLowBound(V, Dim);

  for i := 0 to 7 do
    Int64Rec(i64).Bytes[i] := V[i];
  Result := IntToStr(i64);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //  CDS1ID is an ftAutoInc field, so we need to remove its read-only flag so
  //  that we can assign it a temporary negative value in the OnNewRecord event
  CDS1ID.ReadOnly := False;

  AdoQuery1RowVersion.ProviderFlags := AdoQuery1RowVersion.ProviderFlags - [pfInWhere, pfInUpdate];

  CDS1.Open;
  Caption := IntToStr(CDS1.RecordCount);
end;

procedure TForm1.CDS1AfterPost(DataSet: TDataSet);
begin
  if CDS1.ApplyUpdates(0) = 0 then
    CDS1.Refresh;
end;

procedure TForm1.CDS1AfterDelete(DataSet: TDataSet);
begin
  CDS1.ApplyUpdates(-1);
end;

function TForm1.NextID: Integer;
begin
  Dec(FID);
  Result := FID;
end;

procedure TForm1.CDS1NewRecord(DataSet: TDataSet);
begin
  CDS1.FieldByName('ID').AsInteger := NextID;
  CDS1.FieldByName('IntValue').AsInteger := Random(100);
end;

procedure TForm1.CDS1AfterInsert(DataSet: TDataSet);
begin
  CDS1.Post;
end;

procedure TForm1.CDS1CalcFields(DataSet: TDataSet);
begin
  CDS1RowVerStr.AsString := GetRowVerString(CDS1RowVersion.Value);
end;

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

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