Как я могу реализовать вычисляемые поля с возможностью записи в TDataSet? - PullRequest
9 голосов
/ 18 марта 2011

Мне нужно добавить дополнительные поля в TDataSet, которые не существуют в базовой базе данных, но могут быть получены из существующих полей.Я могу легко сделать это с полями, и это прекрасно работает.

Теперь я хочу отредактировать эти поля и записать измененные данные обратно.Я могу изменить расчет, чтобы записать данные обратно в существующие поля, но элементы управления БД просто не позволяют мне редактировать вычисляемые поля.

Есть ли какой-либо подход, который позволяет мне это делать?

Обновление: Хорошо, некоторые дополнительные сведения о фоне.

В наборе данных есть поле BLOB-объекта, которое представляет собой представление TBytes.Определено, что некоторые байты содержат информацию, которая может быть удобно представлена ​​в существующих полях редактирования БД.Однако не все байты известны, поэтому представление TBytes должно быть таким же, как для обработки через другое приложение, которое знает об этом.Это приложение также изменяет существующие и вставляет новые записи.

ТБайт разных записей в наборе данных часто отображаются на представления различных полей, хотя установка фильтра или диапазона в наборе данных гарантирует, что они имеют одинаковое отображение.

Как я уже сказал, извлечение известных байтов и преобразование их в строки, даты, числа и т. Д. С помощью вычисляемых полей не является проблемой.Преобразование этих значений в TBytes также возможно.Проблема заключается в том, что эти дополнительные поля можно редактировать, сохраняя при этом навигацию по набору данных без изменений.

Если это поможет: у нас есть классы, которые выполняют двунаправленное сопоставление, выставляя поля как опубликованные свойства.

Ответы [ 7 ]

4 голосов
/ 19 марта 2011

Ответ зависит от компонентов доступа к данным, которые вы используете. Я использую Anydac, и он поддерживает поля fkInternalCalc, которые могут быть рассчитаны как отредактированные вручную.

3 голосов
/ 18 марта 2011

У меня была похожая проблема с ClientDataSet, я решил эту проблему с помощью фиктивных файлов на SQL-Stmt, чтобы я мог смоделировать поля в базе данных.

См. Мой Вопрос

3 голосов
/ 18 марта 2011

Я думаю, что вычисленные поля по определению доступны только для чтения, а значения рассчитаны на клиенте. То, что вы хотите, возможно, может быть реализовано с помощью обновляемого представления. Вы можете уже определить представление с вычисляемыми полями - они будут рассчитаны в SQL на сервере - и триггером обновления, а может быть и триггером вставки - для выполнения обратного вычисления. Тогда из клиента вы можете использовать представление прозрачно, как таблица.

1 голос
/ 18 марта 2011

Вы можете использовать TDatasetProvider.OnGetRecords (не помню, если это правильное имя события) и изменить пакет данных, отправленный в набор клиентских данных.

Конечно, вам придется иметь дело с ними в обработчике ApplyUpdates, как сказал TOndrej.

0 голосов
/ 15 сентября 2015

Использование потомка TQuery (MyQuery) с «Выбрать *, 0 как TempField из MyTable»

Procedure MyQueryAfterOpen(Dataset:TDataSet);
Begin
    DataSet.FieldByName('TempField').ReadOnly := False;
End;

Теперь это временное поле editabe

0 голосов
/ 17 апреля 2013

В нашей структуре базы данных некоторые значения являются процентами относительно другого столбца (называемого oMean ниже), тогда как другие значения с плавающей запятой сохраняются как абсолютные значения. Позднее нашим клиентам потребовались оба варианта (отн. И абс.) Для всех полей, поэтому мы придумали следующий класс, полученный из TFloatField. Это должно работать для всех потомков TDataSet.

unit EditableCalcFloatField;

interface

uses
  db, classes;

type
  TEditableCalcFloatField = class(TFloatField)
  public
    oAbs, oRel, oMean: TField;
  protected
    function GetCanModify: Boolean; override;
    procedure SetAsFloat(Value: Double); override;
  end;

implementation

function TEditableCalcFloatField.GetCanModify: Boolean;
begin
  Result := oMean.AsFloat <> 0;
  if not Result then Exit;
  Result := (oAbs <> nil) or (oRel <> nil);
end;

procedure TEditableCalcFloatField.SetAsFloat(Value: Double);
var
  fMean                                 : Double;
begin
  inherited;

  if DataSet.State in [dsEdit, dsInsert] then begin
    fMean := oMean.AsFloat;
    if fMean = 0 then Exit;
    if oAbs <> nil then
      oAbs.AsFloat := Value / 100 * fMean
    else
      oRel.AsFloat := Value / fMean * 100;
  end;
end;

end.

Чтобы использовать его без пакета, вы должны создать поле в FormCreate до открытия набора данных:

with TEditableCalcFloatField.Create(Self) do
begin
  oAbs := sqlMerkmaleYourAbsoluteColumn;
  DisplayLabel := sDisp;
  oMean := sqlMerkmaleAssignedValue_Mean;
  Calculated := True;
  FieldName := 'R' + oAbs.FieldName;
  DataSet := sqlMerkmale;
end;

И, конечно, его содержимое может быть установлено либо в событии OnCalcFields, либо пользователем.

0 голосов
/ 18 марта 2011

Компоненты информационной мощности Woll2Woll (я только что проверил их TwwDBEdit) позволяют делать такие вещи. Поэтому я думаю, что все, что вы блокируете, находится на уровне TDBEdit (или на уровне TFieldDataLink).

Что именно отличается в TwwDBEdit, я не знаю. (И я не уверен, что лицензионное соглашение позволило бы мне публиковать здесь ...).

...