红鱼儿

让kbmMWClientQuery更新视图

先说下问题,有一个物理表t1,基于t1,建立一个视图v1,然后用ClientQuery查询视图:
ClientQuery.Query.Text:='Select f1,f2 from v1'
查询到结果后,增删改记录,然后:
ClientQuery.Resolve提交修改结果,问题出现:

当ClientQuery.TableName='t1'时,可以提交,等于'v1'时,无法提交,生成一个无字段的sql
Insert into v1 ( ) values ( )

那如何让ClientQuery.TableName='v1'时也能正常提交呢?


解决方法:在运行期修改Field.Origin值
ClientQuery.FieldByName('f1').Origin:='v1.f1';
ClientQuery.FieldByName('f2').Origin:='v1.f2';
或者:
ClientQuery.FieldByName('f1').Origin:='.f1';
ClientQuery.FieldByName('f2').Origin:='.f2';
或者:
ClientQuery.FieldByName('f1').Origin:='';
ClientQuery.FieldByName('f2').Origin:='';

视图能正常更新了!注意,必须在运行期用代码来修改Origin,设计期不行的。

进一步分析原因,在ClientQuery.Open后,ClientQuery.FieldByName('f1').Origin等于't1.f1',也就是查询视图,这里返回实际物理表名,在服务端解析时,如果ClientQuery.TableName=v1,与字段的Origin中的物理表名t1不一致,造成无法生成正确的sql语句。

具体的逻辑在TkbmMWCustomTableFieldResolver.BuildFieldFilter方法中实现,感兴趣可以去看看。

通过查看这个方法,得知,当设置Origin为空时,还受kbmMWUNIDACResolver.SkipFieldsWithoutOrigin属性控制,当为True时,则不处理这个字段,默认值为False,即处理Origin为空的字段。

写到这里,也许你已经想到,不仅对于View的更新操作,我们完全可以通过设置ClientQuery.TableName及Field.Origin属性,实现ClientQuery.Resolve的更新行为。这必须为kbmMW赞一个!

最后,感谢Q友不会呼吸274001335,帮我跟踪了好几天,最终搞清这块的逻辑,同时感谢作者kim在news group 上的支持与回复!

下面按不会呼吸的想法,利用Class Helper来修改ClientQuery.Open的行为:

//声明kbmMWClientQuery的Helper类:
  TkbmMWClientQueryHelper=class helper for TkbmMWClientQuery
    procedure Open;
  end;

//重新实现kbmMWClientQuery.Open方法
{ TkbmMWClientQueryHelper }

procedure TkbmMWClientQueryHelper.Open;
var
  i:Integer;
begin
  inherited Open;
  for I := 0 to Self.FieldCount-1 do
  begin
    if Self.Fields[i].Origin.Substring(0,1)<>'.' then //如果是虚字段则设置为一个不存在的表名,保证不生成到sql里去更新
//      Self.Fields[i].Origin:=Self.TableName+'.'+Self.Fields[i].FieldName
      Self.Fields[i].Origin:='.'+Self.Fields[i].FieldName
//      Self.Fields[i].Origin:=''
    else
      //如果是sql中的虚字段则设置为一个不存在的表名,保证不生成到sql里去更新,避免出错.
      Self.Fields[i].Origin:='xxxxxxxxxx.'+Self.Fields[i].FieldName;

  end;

end;

对于Helper Class,执行ClientQuery.Open的单元,必须引用这个Helper类所在的单元,否则不会执行上面的代码!

上面的方法,只是解决当查询一个视图时,自动不提交虚拟字段,那对于下面朋友遇到的问题,又如何处理呢?

朋友HY遇到这样的问题,查询视图,还要修改视图并提交修改结果,因为是视图,有些字段不需要提交到后台。
查了下新闻组,作者提到几种方法可以控制提交哪些字段到后台:
方法一:
通过设置TField.Origin属性,需要提交的填上内容,不需要为空,然后设置服务端的Resolver.SkipFieldWithoutOrigin=True;

方法二:
通过设置TField.ProviderFlags属性,不需要提交的将pfInUpdate去掉。通过这个属性还可以进一步控制字段是否出现在Where子句中。

procedure TPersonManagerFrame.qOneTableAfterOpen(DataSet: TDataSet);
begin
  inherited;
  //不更新这两个字段.
  DataSet.FieldByName('FPositionName').ProviderFlags := DataSet.FieldByName('FPositionName').ProviderFlags- [pfInUpdate,pfInWhere];
  DataSet.FieldByName('FPositionID').ProviderFlags := DataSet.FieldByName('FPositionID').ProviderFlags- [pfInUpdate,pfInWhere];
end;


方法三:
处理Resolver的事件:ExcludeFromUpdateInsert和ExcludeFromWhere,简单返回字段的ProviderFlags,类似方法二。

最后,想说的是:选择kbmMW做你的多层框架,没错的! 

posted on 2020-09-18 18:32  红鱼儿  阅读(463)  评论(1编辑  收藏  举报