Delphi 如何对存储在单个DB字段中的格式化数据使用多个TcxDBTextEdit?

Delphi 如何对存储在单个DB字段中的格式化数据使用多个TcxDBTextEdit?,delphi,devexpress,ado,tadoquery,tdxmemdata,Delphi,Devexpress,Ado,Tadoquery,Tdxmemdata,我需要在一个数据库字段中存储两个值(是的,我同意这是一种不好的做法,但这是一个无法更改的遗留数据库)。数据存储为string1#4string2 数据需要使用两个单独的TcxDBTextEdit控件进行编辑。但是如何将它们连接到单个数据库字段,以便在其中一个字段中编辑string1,在另一个字段中编辑string2 我尝试将两个计算(fkcomputed)字段添加到TADOQuery,在OnGetText/OnSetText中提取/合并它们的值,并读取/写入TStringField,但没有成功

我需要在一个数据库字段中存储两个值(是的,我同意这是一种不好的做法,但这是一个无法更改的遗留数据库)。数据存储为
string1#4string2

数据需要使用两个单独的
TcxDBTextEdit
控件进行编辑。但是如何将它们连接到单个数据库字段,以便在其中一个字段中编辑
string1
,在另一个字段中编辑
string2

我尝试将两个计算(
fkcomputed
)字段添加到
TADOQuery
,在
OnGetText
/
OnSetText
中提取/合并它们的值,并读取/写入
TStringField
,但没有成功

因此,我尝试创建一个包含两个字段的
TdxMemData
组件,并使用它们代替计算字段,但仍然不起作用


如何实现这一点(而不改变数据库结构)?

下面的示例项目似乎满足了您的需求

更新下面的代码替换了我最初发布的代码,避免了使用 属于支持fkInternalCalc字段的数据集类型(TClientDataSet)。它 用一种轻描淡写的方式工作

虽然将字符串字段解析为两个子字段原则上没有困难 并将它们呈现在gui中进行编辑,这是使用简单方法进行编辑的问题 问题是,它只支持FKComputed字段和支持db的gui控件 将其视为用户不可修改

我不确定为什么会存在这种限制,但我想这与以下事实有关: Delphi的db aware控件最初是为BDE开发的(在之前的aby案例中也是如此) 添加fkInternalCalc以支持TClientDataSet)。DB.Pas中强制执行的代码 限制以DB.Pas为单位:

function TField.GetCanModify: Boolean;
begin
  if FieldNo > 0 then
    if DataSet.State <> dsSetKey then
      Result := not ReadOnly and DataSet.CanModify else
      Result := IsIndexField
  else
    Result := False;
end;
下面是一个示例项目的完整代码。请注意,我使用的是正则表达式 因为我当前的Devex设置有问题,但是代码应该 使用TcxDBEdit也可以很好地工作

代码:

类型
TStringField=class(db.TStringField)
受保护的
函数GetCanModify:Boolean;推翻
结束;
类型
TForm1=类(TForm)
DBGrid1:TDBGrid;
DBNavigator1:TDBNavigator;
数据源1:TDataSource;
DBEdit1:TDBEdit;
DBEdit2:TDBEdit;
ADOQuery1:TADOQuery;
cxDBMaskEdit1:TcxDBMaskEdit;
DBEdit3:TDBEdit;
b数据链接:t按钮;
ADO连接1:TADOConnection;
ADOQuery1ID:TIntegerField;
ADOQuery1Field1:TWideStringField;
ADOQuery1Field2:TWideStringField;
ADOQUERY1子字段1:T字符串字段;
ADOQUERY1子字段2:TStringField;
过程表单创建(发送方:ToObject);
过程ADOQuery1BeforePost(数据集:TDataSet);
程序ADOQuery1CalcFields(数据集:TDataSet);
私有的
过程更新子字段(数据集:TDataSet);
过程UpdateField1(数据集:TDataSet);
结束;
[...]
常数
scSeparator='#4';//可以是文字4
过程TForm1.UpdateField1(数据集:TDataSet);
变量
S:字符串;
开始
如果DataSet.FieldByName('SubField1').IsNull或DataSet.FieldByName('SubField2').IsNull,则退出;
S:=DataSet.FieldByName('SubFieldD1')。AsString+scSeparator+
DataSet.FieldByName('SubField2').AsString;
S:=修剪;
如果长度>DataSet.FieldByName('Field1')。大小,则
引发异常。创建('t子字段的组合大小太长');
DataSet.FieldByName('Field1')。关联字符串:=S;
结束;
过程TForm1.UpdateSubFields(数据集:TDataSet);
变量
s
SF1,
SF2:字符串;
P
SF2Start:整数;
开始
S:=DataSet.FieldByName('Field1').AsString;
P:=位置(SCS分离器);
SF1:=副本(S,1,P-1);
SF1:=微调(SF1);
SF2Start:=P+长度(scSeparator);
SF2:=副本,Sf2Start,长度;
SF2:=微调(SF2);
DataSet.FieldByName('SubField1')。关联字符串:=SF1;
DataSet.FieldByName('SubField2')。关联字符串:=SF2;
结束;
过程TForm1.FormCreate(发送方:TObject);
开始
AdoQuery1.打开;
结束;
程序TForm1.CDS1CalcFields(数据集:TDataSet);
开始
更新子字段(数据集);
结束;
函数TStringField.GetCanModify:Boolean;
开始
如果(FieldKind=FKComputed)和DataSet.CanModify而非ReadOnly,则
结果:=真
其他的
如果是DataSet.State dsSetKey,则
结果:=不只读且DataSet.CanModify else
结果:=IsIndexField
结束;
过程TForm1.ADOQuery1BeforePost(数据集:TDataSet);
开始
更新字段1(AdoQuery1);
结束;
过程TForm1.ADOQuery1CalcFields(数据集:TDataSet);
开始
更新子字段(数据集);
结束;

恐怕“不起作用”不是一个有用的问题描述。同样,您需要添加一个。我想,第一个“不起作用”指的是计算字段无法编辑的事实。看看这个问题和公认的答案:那么,我的答案的更新版本是否回答了您的问题?
function TStringField.GetCanModify: Boolean;
begin
  if (FieldKind = fkCalculated) and DataSet.CanModify and not ReadOnly then
    Result := True
  else
  if DataSet.State <> dsSetKey then
    Result := not ReadOnly and DataSet.CanModify else
    Result := IsIndexField
end;
type
  TStringField = class(db.TStringField)
  protected
    function GetCanModify : Boolean; override;
  end;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    DataSource1: TDataSource;
    DBEdit1: TDBEdit;
    DBEdit2: TDBEdit;
    ADOQuery1: TADOQuery;
    cxDBMaskEdit1: TcxDBMaskEdit;
    DBEdit3: TDBEdit;
    btnDataLinks: TButton;
    ADOConnection1: TADOConnection;
    ADOQuery1ID: TIntegerField;
    ADOQuery1Field1: TWideStringField;
    ADOQuery1Field2: TWideStringField;
    ADOQuery1SubField1: TStringField;
    ADOQuery1SubField2: TStringField;
    procedure FormCreate(Sender: TObject);
    procedure ADOQuery1BeforePost(DataSet: TDataSet);
    procedure ADOQuery1CalcFields(DataSet: TDataSet);
  private
    procedure UpdateSubFields(DataSet : TDataSet);
    procedure UpdateField1(DataSet: TDataSet);
  end;

[...]
const
  scSeparator = '#4';   // could be a literal #4 instead

procedure TForm1.UpdateField1(DataSet : TDataSet);
var
  S : String;
begin
  if DataSet.FieldByName('SubField1').IsNull or DataSet.FieldByName('SubField2').IsNull then exit;

  S := DataSet.FieldByName('SubField1').AsString + scSeparator +
    DataSet.FieldByName('SubField2').AsString;
  S := Trim(S);
  if Length(S) > DataSet.FieldByName('Field1').Size then
    raise exception.Create('tthe combined size of the subfields is too long');

  DataSet.FieldByName('Field1').AsString := S;
end;

procedure TForm1.UpdateSubFields(DataSet : TDataSet);
var
  S,
  SF1,
  SF2 : String;
  P,
  SF2Start : Integer;
begin
  S := DataSet.FieldByName('Field1').AsString;
  P := Pos(scSeparator, S);
  SF1 := Copy(S, 1, P-1);
  SF1 := Trim(SF1);
  SF2Start :=  P + Length(scSeparator);
  SF2 := Copy(S, Sf2Start, Length(S));
  SF2 := Trim(SF2);

  DataSet.FieldByName('SubField1').AsString := SF1;
  DataSet.FieldByName('SubField2').AsString := SF2;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  AdoQuery1.Open;
end;

procedure TForm1.CDS1CalcFields(DataSet: TDataSet);
begin
  UpdateSubFields(DataSet);
end;

function TStringField.GetCanModify: Boolean;
begin
  if (FieldKind = fkCalculated) and DataSet.CanModify and not ReadOnly then
    Result := True
  else
  if DataSet.State <> dsSetKey then
    Result := not ReadOnly and DataSet.CanModify else
    Result := IsIndexField
end;

procedure TForm1.ADOQuery1BeforePost(DataSet: TDataSet);
begin
  UpdateField1(AdoQuery1);
end;

procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
begin
  UpdateSubFields(DataSet);
end;