三层救命题(200分)

  • 主题发起人 主题发起人 goldstone
  • 开始时间 开始时间
G

goldstone

Unregistered / Unconfirmed
GUEST, unregistred user!
在三层中,我通过clientdataset.applyupdate(0)向服务器提交插入操作,由于其中的id是种子型,我在客户端无法取得,既clientdataset新插入的记录中id字段是空,实际是有值的,如何让
他在clientdataset可以取到,谢谢!!!
 
先假提交得到具体值,如果客户端取消再删除。
 
有没有更好的办法
 
把id的类型换成自己可以控制的不就行了。。
如:自己去数据库里查一下取最大的id号然后加1.
 
可是你总有自己不能控制的吧,比如要求插入系统时间,等等,我想肯定会有这样的情况吧,我主要是想解决这样的问题
 
比如你想把insert table (s1,datetime) values(@s1,getdate())这个datetime如何在更新完后返回到
ClientDataset去呢,大家多想想办法吧,也许你们以后也会用到
 
在应用程序服务器端写一个方法,
该方法:
先执行 insert into table (s1,datetime) values(@s1,getdate())插入记录,
然后用:@@IDENTITY(返回最后插入的标识值。)其具体用法如下
{语法
@@IDENTITY
返回类型
numeric
注释
在一条 INSERT、SELECT INTO 或大容量复制语句完成后,@@IDENTITY 中包含此语句产生的最后的标识值。若此语句没有影响任何有标识列的表,则 @@IDENTITY 返回 NULL。若插入了多个行,则会产生多个标识值,@@IDENTITY 返回最后产生的标识值。如果此语句激发一个或多个执行产生标识值的插入操作的触发器,则语句执行后立即调用 @@IDENTITY 将返回由触发器产生的最后的标识值。若 INSERT 或 SELECT INTO 语句失败或大容量复制失败,或事务被回滚,则 @@IDENTITY 值不会还原为以前的设置。
在返回插入到表的 @@IDENTITY 列的最后一个值方面,@@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 函数类似。
@@IDENTITY 和 SCOPE_IDENTITY 将返回在当前会话的所有表中生成的最后一个标识值。但是,SCOPE_IDENTITY 只在当前作用域内返回值,而 @@IDENTITY 不限于特定的作用域。
IDENT_CURRENT 不受作用域和会话的限制,而受限于指定的表。IDENT_CURRENT 返回任何会话和任何作用域中为特定表生成的标识值。有关更多信息,请参见 IDENT_CURRENT。
示例
下面的示例向带有标识列的表中插入一行,并用 @@IDENTITY 显示在新行中使用的标识值。
INSERT INTO jobs (job_desc,min_lvl,max_lvl)
VALUES ('Accountant',12,125)
SELECT @@IDENTITY AS 'Identity'
这个datetime如何在更新完后返回到
ClientDataset去
}

利用:@@IDENTITY 返回你插入的 ID 号,给应用程序服务器,在传给客户端,
顺便问一下,你用的是SQLSERVER 还是 Orcale
若是Orcale 则直接用
(Oracle 里的种子用SQL语句赋值如:SQ_ORDER_FORM是种子型,用
SQ_ORDER_FORM.NEXTVAL赋新值;SQ_ORDER_FORM.CURRVAL取当前值)
 
如果ID是数据库的序列号,TIME是数据库时间,则可写触发器解决之。
如果ID和TIME要在中间层获取:
在DataSetProvider的BeforeUpdateRecord中,写以下代码:
procedure TForm1.DataSetProvider1BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
begin
if UpdateKind <> ukDelete and
begin
DeltaDS.FieldByName('ID').AsInteger := GetID;
DeltaDS.FieldByName('Time').AsDateTime := Now;
end;
end;
 
噢,写错:应该是新增记录:
if UpdateKind <> ukInsert and
...
 
:(
if UpdateKind = ukInsert and
 
看了看,还是可能有错(没有EDIT和POST),你自己试试改看行不行吧。
procedure TForm1.DataSetProvider1BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
begin
if UpdateKind = ukInsert then
begin
DeltaDS.Edit;
DeltaDS.FieldByName('ID').AsInteger := GetID;
DeltaDS.FieldByName('Time').AsDateTime := Now;
DeltaDS.Post;
end;
end;
 
Huzzz:首先谢谢你,你的这种方法做过,delta里的数据我都改变了,但是clientdataset还是没有取得到,
不知道是为什么?

free_knight:你好,你的这种方法我在此之前已经做过,没有用的,我现在的问题是如何在应用服务器里
将Delta的数据返回给clientdataset,本来是delta里的数据在提交结束后会自动返回给clientdataset,我只要
改变delta里的数据就可以了,可是这样还是不行,clientdataset还是没有得到,不知道为什么?
你们有没有这样的问题,试试看,分数可以继续增加!
再次谢谢大家!!!!

 
我用的是sql server
 
除非UPDATE出错,否则delta里的数据在提交结束后是不会返回给clientdataset的,
UPDATE成功时将返回NULL。
但我们可以自己把更改过的delta记录下来并返回给客户端。
下面是我的思路,我没有具体试,但我觉得是可行的:
//在服务端,用一个ClientDataSetUpateLog记录更新中被改变的记录,在更新前清空:
procedure TMyDM.DataSetProvider1BeforeApplyUpdates(Sender: TObject;
var OwnerData: OleVariant);
begin
OwnerData := NULL;
ClientDataSetUpateLog.Close;
end;

//更新时进行记录,并记录旧的ID:
procedure TMyDM.DataSetProvider1BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
var
I, OldID: Integer;
function GetID: Integer;
begin
Result := -1;
end;
begin
if UpdateKind = ukInsert then
begin
if not ClientDataSetUpateLog.Active then
begin
ClientDataSetUpateLog.FieldDefs.Clear;
for I := 0 to DeltaDS.FieldCount - 1do
ClientDataSetUpateLog.FieldDefs.Add(
DeltaDS.Fields.Fields.FieldName,
DeltaDS.Fields.Fields.DataType,
DeltaDS.Fields.Fields.Size,
DeltaDS.Fields.Fields.Required);
ClientDataSetUpateLog.FieldDefs.Add(
'OLDID',
DeltaDS.FieldByName('ID').DataType,
DeltaDS.FieldByName('ID').Size,
DeltaDS.FieldByName('ID').Required);
//记录旧的ID
ClientDataSetUpateLog.CreateDataSet;
end;

OldID := DeltaDS.FieldByName('ID').AsInteger;
DeltaDS.Edit;
DeltaDS.FieldByName('ID').AsInteger := GetID;
DeltaDS.FieldByName('Time').AsDateTime := Now;
DeltaDS.Post;
ClientDataSetUpateLog.Append;
for I := 0 to DeltaDS.FieldCount - 1do
ClientDataSetUpateLog.Fields.Fields.Value :=
DeltaDS.Fields.Fields.Value;
ClientDataSetUpateLog.FieldByName('OldID').AsInteger := OldID;
ClientDataSetUpateLog.Post;
end;
end;

//更新后打包并返回:
procedure TMyDM.DataSetProvider1AfterApplyUpdates(Sender: TObject;
var OwnerData: OleVariant);
begin
if not ClientDataSetUpateLog.Active then
OwnerData := NULL
else
begin
ClientDataSetUpateLog.MergeChangeLog;
OwnerData := ClientDataSetUpateLog.Data;
end;
end;

//在客户端获得改变过的更新记录:
procedure TForm1.ClientDataSet1AfterApplyUpdates(Sender: TObject;
var OwnerData: OleVariant);
begin
if OwnerData <> NULL then
CDSUpdateChgs.Data := OwnerData
else
CDSUpdateChgs.Close;
end;

//在UPDATE后客户端将改变过的更新记录刷新:
procedure TForm1.Button1Click(Sender: TObject);
var
I, OldID: Integer;
begin
ClientDataSet1.ApplyUpdates(0);
if CDSUpdateChgs.Active then
with CDSUpdateChgsdo
begin
First;
while not EOFdo
begin
OldID := CDSUpdateChgs.FieldByName('OldID').AsInteger;
if ClientDataSet1.Locate('ID', OldID, []) then
begin
ClientDataSet1.Edit;
ClientDataSet1.FieldByName('ID').Value :=
CDSUpdateChgs.FieldByName('ID').Value;
ClientDataSet1.FieldByName('Time').Value :=
CDSUpdateChgs.FieldByName('Time').Value;
ClientDataSet1.Post;
end;
Next;
end;
ClientDataSet1.MergeChangeLog;
end;
end;
 
Huzzz先谢谢你了,其实我是想通过别的更简单的方法,你这种方法我用过,其实如果要这样将整个数据从服务器
传回来,大可不必,只要将修改过的id和time通过OwnerData打包回给clientdataset就可以了,
完全没有必要整个打包回来,大家再想想,有没有更好的办法,谢谢了

再次谢谢Huzzz和为此问题辛苦的各位
 
你看仔细了,我正是:将修改过的id和time通过OwnerData打包回给clientdataset
而不是:整个打包回来。
!!!
 
看仔细点,我正是“将修改过的id和time通过OwnerData打包回给clientdataset”,
而不是“整个打包回来”。
!!!
 
请问您用的中间层记录集是什么?我用AdoDataSet连接SQL Server,只要在ApplyUpdate之后
调用ClientDataSet的Refresh方法即可获得种子字段的值。
 
如果我没有理解错:
你的最终目的是要把插入刚插入的记录在客户端反映出来是不是?
并且不能用clientdataset.close;clientdataset.open;这种笨办法是不是?
最有效的方法是把刚添加的记录直接取过来是不是?
因此就需要刚添加的记录的ID号是不是?
还有你用的是sql server是不是?
CREATE PROCEDURE table_insert @table_cursor CURSOR VARYING OUTPUT
AS
insert table (s1,datetime) values(@s1,getdate())
SET @table_cursor = CURSOR FOR SELECT * from table where ID = @@IDENTITY
OPEN @table_cursor
GO
这样就能取到刚插入的那条记录是不是?
 
whsunbin 将中间层DataSetProvider控件的poPropogateChange属性改为True还是不行,帮忙看看程序
procedure TagentserverRDM.dspGetXingyeBeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet;
DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind;
var Applied: Boolean);
begin
if UpdateKind =Ukinsert then
begin
deltaDs.Edit;
deltaDs.FieldByName('Postdate').Value :=now;
deltaDs.FieldByName('id').Value :=11111;
deltaDs.post;
end;
UpdateXingye(DeltaDS, UpdateKind);
Applied:=true;
end;


procedure TagentserverRDM.UpdateXingye(DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind);
begin
case UpdateKind of
ukInsert: //增加
begin
AssignFieldValue(DeltaDS, spXingyeInsert, 'Id', '@id');
AssignFieldValue(DeltaDS, spXingyeInsert, 'PostDate', '@postdate');
AssignFieldValue(DeltaDS, spXingyeInsert, 'Title', '@Title');
AssignFieldValue(DeltaDS, spXingyeInsert, 'content', '@content');
AssignFieldValue(DeltaDS, spXingyeInsert, 'origin', '@origin');
AssignFieldValue(DeltaDS, spXingyeInsert, 'from_url', '@from_url');
spXingyeInsert.ExecProc;
end;
ukModify : //修改
begin
AssignFieldValue(DeltaDS, spXingyeEdit, 'Title', '@Title');
AssignFieldValue(DeltaDS, spXingyeEdit, 'content', '@content');
AssignFieldValue(DeltaDS, spXingyeEdit, 'origin', '@origin');
AssignFieldValue(DeltaDS, spXingyeEdit, 'from_url', '@from_url');
spXingyeEdit.ExecProc;
end;
ukDelete : //删除
begin
spXingyeDelete.Parameters.ParamByName('@ID').Value := DeltaDS.FieldByName('Id').Asstring;
spXingyeDelete.ExecProc;
end;
end;
end;


procedure TagentserverRDM.AssignFieldValue(DeltaDS: TCustomClientDataSet;
adostore : TADOStoredProc;
const sField, sID : string);
var
aField : TField;
Value: Variant;
begin
aField := DeltaDS.FieldByName(sField);
Value := aField.NewValue;
if VarIsEmpty(Value) then
adostore.Parameters.ParamByName(sID).Value := aField.OldValue
else
adostore.Parameters.ParamByName(sID).Value := Value;
end;


结果在客户端还是没有得到id和postdate,拜托大家了
 
后退
顶部