简体   繁体   English

如何将多个TcxDBTextEdit与格式化的数据一起存储在单个DB字段中?

[英]How can I use multiple TcxDBTextEdit with formatted data stored in a single DB field?

I have a need to store two values in a single database field (yes, I agree that it is bad practice, but this is a legacy database that can't be altered). 我需要在一个数据库字段中存储两个值(是的,我同意这是不好的做法,但这是无法更改的旧数据库)。 The data is stored as string1#4string2 . 数据存储为string1#4string2

The data needs to be edited using two separate TcxDBTextEdit controls. 数据需要使用两个单独的TcxDBTextEdit控件进行编辑。 But how can I connect them to the single database field so that I can edit string1 in one and string2 in the other? 但是,如何将它们连接到单个数据库字段,以便可以在一个数据库中编辑string1在另一个数据库中编辑string2

I've tried adding two calculated ( fkCalculated ) fields to the TADOQuery , extracting/joining their values in OnGetText / OnSetText and reading/writing to the TStringField , but it didn't work. 我尝试将两个计算( fkCalculated )字段添加到TADOQuery ,在OnGetText / OnSetTextOnGetText / OnSetText它们的值,并读/写到TStringField ,但这没有用。

So I tried creating a TdxMemData component with two fields and using them instead of the calculated fields, but it still doesn't work. 因此,我尝试使用两个字段创建一个TdxMemData组件,并使用它们代替计算字段,但是仍然无法正常工作。

How can I achieve this (without altering the database structure)? 我该如何实现(不更改数据库结构)?

The sample project below does what you seem to want. 下面的示例项目可以满足您的需求。

Update The code below replaces the code I originally posted and avoids the use of a dataset type (TClientDataSet) which supports fkInternalCalc fields. 更新下面的代码替换了我最初发布的代码,并避免使用支持fkInternalCalc字段的数据集类型(TClientDataSet)。 It will work with a TAdoQuery. 它将与一个TAdoQuery工作。

Although there is no difficulty in principle in parsing a string field into two subfields and surfacing them in your gui for editing, the problem with straightforward ways of doing this with a TAdoQuery is that it only supports fkCalculated calculated fields and db-aware gui controls treat these as not modifiable by the user. 尽管原则上将字符串字段解析为两个子字段并在gui中将其覆盖以进行编辑并不困难,但是使用TAdoQuery进行直接操作的问题在于它仅支持fkCalculated计算字段和db-agui gui控件这些是用户无法修改的。

I'm not sure why this restriction exists, but I imagine that it is related to the fact that Delphi's db-aware controls were originally developed for the BDE (and in aby case before fkInternalCalc was added to support TClientDataSet). 我不确定为什么存在此限制,但是我想这与Delphi的db-aware控件最初是为BDE开发的(以及在添加fkInternalCalc以支持TClientDataSet之前的一种情况)有关。 The code in DB.Pas which enforces the restriction is in DB.Pas: 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;

The code below works by adding an interposer class for TStringField which removes the restriction for stringfields whose FieldKind is fkCalculated which are not ReadOnly and belong to a dataset which is modifiable (though this latter restriction could be removed, I think). 下面的代码通过为TStringField添加一个插入器类来工作,该插入器类消除了对FieldKind为fkCalculated的字符串字段的限制,这些字符串字段不是ReadOnly且属于可修改的数据集(尽管我认为可以删除后一个限制)。 The interposer TStringField overrides GetCanModify like so: 插入器TStringField重写GetCanModify如下所示:

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;

The full code of an example project is below. 示例项目的完整代码如下。 Note that I've used regular TDBEdits because I have a problem with my current Devex set-up but the code should work fine with TcxDBEdit as well. 请注意,我使用常规的TDBEdits是因为我当前的Devex设置存在问题,但是代码也可以在TcxDBEdit上正常工作。

Code: 码:

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;

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

相关问题 如何使用 Indy 向存储在 TListView 组件中的多个 email 地址发送消息? - How can I use Indy to send messages to multiple email addresses that are stored within a TListView component? 如何在单个表单上创建多个单选按钮组? - How can I create multiple radio button groups on a single form? 如何存储和查看图形格式的数据? - How do I store and view graphically formatted data? 如何在MS Access中创建一个名为SECTION的数据库表字段? - How can I create a DB table field called SECTION in MS Access? 如何使用TADODataset创建和使用聚合字段? - How can I create and use aggregate field with TADODataset? 如何正确对齐 FastReport 中的数字数据字段 - How can I right justify a numeric data field in FastReport 如何在DrawCell上修改数据库字段的文本? TcxGrid - How can I modify the text of a data base field on DrawCell? TcxGrid 如何使用 stringgrid 单元格的值存储在应该保存当前游戏 state 的数组中? - How can I use the value of a stringgrid cell to be stored in an array which should hold the current game state? 如何执行存储在数据库中的代码? - How can I execute code stored in a database? 如何将多个用户的Access数据库迁移到一个SQLServer数据库 - How to migrate multiple users' Access db's to one single SQLServer db
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM