Трехзвенка на Delphi 3 + MS Access + ODBC + BDE
От: PGrinevich  
Дата: 02.10.03 07:03
Оценка:
Уважаемые профессионалы!
Для простоты описания проблемы пример несколько гипотетичен.
На форе расположены:
TDatabase, подлюченный к MS Access через ODBC-драйвер,
TTable, TProvider, TClientDataSet.
При вызове ApllyUpdates после добавлении записей в TClientDataSet
возникает ошибка:
> Invalid field name.
> [Microsoft][Драйвер ODBC Microsoft Access] Инструкция INSERT INTO содержит неизвестное имя поля 'CLASS.ID'.
> Прверьте, что ...
Очевидно MS Access не понимает синтаксиса CLASS.ID при выполнении операции INSERT,
поле ID в таблице CLASS существует.
Изменение и удаление записей такой ошибки не вызывают.
При использованиии вместо ODBC драйвера Native драйвера BDE таких проблем не возникает, но
возникают другие, ... Поэтому хотелось бы услышать совета по решению проблемы связки
BDE->ODBC->Access.
Re: Трехзвенка на Delphi 3 + MS Access + ODBC + BDE
От: Callisto  
Дата: 02.10.03 08:03
Оценка:
А почему не подходит использование ADO ?
Re[2]: Трехзвенка на Delphi 3 + MS Access + ODBC + BDE
От: PGrinevich  
Дата: 02.10.03 08:10
Оценка:
На само деле — это большой проект на Delphi 3
c поддержкой нескольких баз данных, и т.д. и в ходе
развития проекта заказчику потребовалась поддержка MS Access!
Использование BDE заложено в основе проекта и изменить это невозможно,
как бы не хотелось
Я пробывал то же самое на Delphi 7 — все работает, но проект то на Delphi 3,
и с этим то же ничего нельзя поделать.
Re[3]: Трехзвенка на Delphi 3 + MS Access + ODBC + BDE
От: PGrinevich  
Дата: 03.10.03 07:55
Оценка:
Проблема разрешилась перекрытием метода ApplyUpdates в провайдере.
Решение не лишено недостатков, но по крайней мере это работает.

function TMyProvider.ApplyUpdates(Delta: OleVariant; MaxErrors: Integer;
  out ErrorCount: Integer): OleVariant;
var
  ds: TClientdataSet;
  i: Integer;
  qUp: TQuery;       // TQuery для выполнения запроса на добавление
  sql: String;       // текст запроса на добавление записей
  fl: TStrings;      // список имен полей
  tn: String;        // имя таблицы

  // True - если все записи в Delta на добавление
  function _usok: Boolean;
  begin
    Result := True;
    ds.First;
    while Result and not ds.EOF do
    begin
      Result := (ds.UpdateStatus = usInserted);
      ds.Next;
    end;
  end;

  // выделить имя таблицы, к которой привязан провайдер
  // пустая строка если неудача (несколько таблиц в select)
  function _etn: String;
  var
    s: TStrings;
  begin
    Result := '';
    if DataSet is TTable then
      Result := TTable(DataSet).TableName
    else
    if DataSet is TQuery then
    begin
      // процедура SQLExtractDependedTables выделяет имена таблиц учавствующих в запросе
      s := SQLExtractDependedTables(TQuery(DataSet).SQL.Text);
      try
        if (s.Count = 1) then
          Result := s[0];
      finally
        s.Free;
      end;
    end;
  end;

  // построить список полей
  function _bfl: TStrings;
  var
    i: Integer;
  begin
    Result := TStringList.Create;
    for i := 0 to ds.FieldCount-1 do
      Result.AddObject(ds.Fields[i].FieldName, ds.Fields[i]);
  end;

begin
  ds := TClientdataSet.Create(nil);
  try
   ds.Data := Delta;
   tn := _etn;
   // если запрос
   if (tn <> '') and _usok then
     try
       qUp := TQuery.Create(nil);
       try
         // привязка к базе данных
         qUp.SessionName := DataSet.SessionName;
         qUp.DatabaseName := DataSet.DatabaseName;
         sql := Format('INSERT INTO %s (', [tn]);
         // формируем SQL на добавление
         fl  := _bfl;
         try
           // поля
           for i := 0 to fl.Count-2 do
             sql := sql + fl[i] + ',';
           sql := sql + fl[fl.Count-1] + ') VALUES (';
           // параметры
           for i := 0 to fl.Count-2 do
             sql := sql + ':' + fl[i] + ',';
           sql := sql + ':' + fl[fl.Count-1] + ')';
           qUp.SQL.Text := sql;
           qUp.Prepare;
           // по всем записям
           ds.First;
           while not ds.EOF do
           begin
             // заполняем параметры
             for i := 0 to fl.Count-1 do
               qUp.ParamByName(fl[i]).AssignField(TField(fl.Objects[i]));
             // добавляем запись
             qUp.ExecSQL;
             // перход к следующей записи
             ds.Next;
           end;
           // все хорошо - очищаем Delta
           Delta := null;
         finally
           fl.Free;
         end;
       finally
         qUp.Free;
       end;
     except
       // ошибка при добавлении записи ???
     end;
     if Not VarIsNull(Delta) then
       Result := inherited ApplyUpdates(Delta, maxErrors, ErrorCount)
     else
       Result := null;
  finally
    ds.Free;
  end;
end;
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.