Невозможно выполнить вставку с помощью клиента datasnap

Я экспериментирую с datasnap (никогда не использовал его раньше) и столкнулся со странной проблемой. Может я что не так делаю, не знаю. Я поместил Clientdataset3 в свою форму. Связал его с SQLConnection1 (в той же форме), который подключается к серверу datasnap. Я также связал Clientdataset3 с поставщиком набора данных (который разрешает текст команды) на стороне сервера, который связан с таблицей, в которую я хочу вставить. Однако, когда я бегу:

procedure TForm3.AdvGlowButton1Click(Sender: TObject);
begin
clientdataset3.CommandText:='insert into "MY_TABLE" (twit) values (:A)';
clientdataset3.Params.ParamByName('A').AsString := cxmemo1.Lines.Text;
clientdataset3.Execute;
end;

Я получаю "Удаленная ошибка: нет такой таблицы: вставить"

Что я делаю не так ? База данных - это SQLite через DBX с использованием XE6.


person user763539    schedule 21.07.2014    source источник


Ответы (1)


Если вы заполняете CDS с помощью оператора SELECT, вам не нужно выполнять упражнение по отправке специального оператора INSERT.

Вы должны иметь возможность просто позвонить

ClientDataSet3.Insert;
// populate fields here
ClientDataSet3.Post;

Затем следует вызов ClientDataSet3.ApplyUpdates.

Точно так же вы можете выполнить DELETE, просто вызвав ClientDataSet3.Delete.

Созданием необходимых операторов INSERT, DELETE и UPDATE занимается поставщик CDS. Однако я не утверждаю, что вы не можете выполнить INSERT так, как вы пытаетесь - он должен работать нормально.

Отсюда я не могу сказать, что не так с вашим INSERT, поэтому вместо этого вот некоторый код, который работает для меня (включая операторы CREATE TABLE и т. д.), чтобы вы, возможно, могли «увидеть разницу». Я использую XE6 на 64-разрядной версии Win7 и версию 3.8.5.0 sqlite3.dll от 4 июня 2014 года.

Пример кода предоставляет 3 способа (все проверенные и работающие) выполнения вставки: два с использованием пользовательских операторов INSERT и третий с использованием поведения вставки по умолчанию CDS, которое можно вызвать в коде (CDS1.Insert) и щелкнув значок ' +' на DBNavigator. Поведение вставки CDS по умолчанию требует специальной обработки: хотя столбец ID на сервере определен как Autoinc, получить значение autoinc при выполнении вставки CDS проблематично, поэтому в коде используется метод, описанный здесь:

http://edn.embarcadero.com/article/20847

создания временного отрицательного значения идентификатора, которое заменяется в процессе применения CDS ApplyUpdates. Обратите внимание, что в DFM указано, что мера, упомянутая в разделе "Ошибки" ссылки относительно ProviderFlags в поле идентификатора SqlQuery, необходима, поскольку значение столбца идентификатора на сервере представляет собой 64-разрядное целое число.

type
  TDataOperation = (doCreateTable, doDropTable, doInsert, doInsertUsingParams, doSelect);

TForm3 = class(TForm)
[...]
{ private declarations }
  ID : Int64;
  function NextID : Int64;
[...]
end;

implementation

{$R *.dfm}

const
  scCreateTable = 'CREATE TABLE [MATable2] ([ID] INTEGER NOT NULL '
    + #13#10 + 'PRIMARY KEY AUTOINCREMENT,  [AName] VARCHAR(20), '
    + #13#10 + '  [AMemo] MEMO)';

  scDropTable =
    'DROP TABLE [MATable2]';

  scInsert1 =
    'INSERT INTO [MATable2] (AName, AMemo) VALUES(''a'', ''A memo'')';

  scSelect =
    'SELECT * FROM [MATable2]';

  scInsertUsingParams =
    'INSERT INTO [MATable2] (AName, AMemo) VALUES(:AName, :AMemo)';

procedure TForm3.PerformTableOperation(Operation : TDataOperation);
var
  Param : TParam;
begin
  if {(Operation in [toCreate, toDrop]) and} CDS1.Active then
    CDS1.Close;
  case Operation of
    doCreateTable : begin
      CDS1.CommandText := scCreateTable;
      CDS1.Execute;
      PerformTableOperation(doSelect);
    end;
    doDropTable : begin
      CDS1.CommandText := scDropTable;
      CDS1.Execute;
    end;
    doSelect : begin
      CDS1.CommandText := scSelect;
      CDS1.Open;
    end;
    doInsert : begin
      CDS1.CommandText := scInsert1;
      CDS1.Execute;
      PerformTableOperation(doSelect);
    end;
    doInsertUsingParams : begin

      CDS1.CommandText := scInsertUsingParams;
//      CDS1.FetchParams;
      CDS1.Params.ParamByName('AName').AsString:= 'bcdef';
      CDS1.Params.ParamByName('AMemo').AsString := 'memo b';
      CDS1.Execute;
      CDS1.Params.Clear;

      PerformTableOperation(doSelect);
    end;
  end;
  if CDS1.Active then  // it won't be  after a toDrop
    CDS1.ApplyUpdates(-1);
end;


procedure TForm3.OpenConnection;
begin
 SqlConnection1.Open;
end;

procedure TForm3.btnCreateClick(Sender: TObject);
begin
  PerformTableOperation(doCreateTable);
end;

[etc ...]

procedure TForm3.btnReopenClick(Sender: TObject);
begin
  CDS1.Close;
  PerformTableOperation(doSelect);
end;

procedure TForm3.btnSelectClick(Sender: TObject);
begin
  PerformTableOperation(doSelect);
end;

procedure TForm3.CDS1AfterDelete(DataSet: TDataSet);
begin
  CDS1.ApplyUpdates(-1);
end;

procedure TForm3.CDS1AfterPost(DataSet: TDataSet);
begin
  CDS1.ApplyUpdates(-1);
end;

procedure TForm3.CDS1NewRecord(DataSet: TDataSet);
begin
  CDS1.FieldByName('ID').AsInteger := NextID;
end;

function TForm3.NextID: Int64;
begin
  Dec(ID);
  Result := ID;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  OpenConnection;
end;

end.

И вот частичный DFM, чтобы свести к минимуму необходимость угадывать, как настроены мои компоненты БД.

object Form3: TForm3
[...]
  object DBGrid1: TDBGrid
    Left = 8
    Top = 8
    Width = 456
    Height = 193
    DataSource = DataSource1
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
    Columns = <
      item
        Expanded = False
        FieldName = 'ID'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'AName'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'AMemo'
        Visible = True
      end>
  end
  [...]
  object DBNavigator1: TDBNavigator
    Left = 16
    Top = 216
    Width = 240
    Height = 25
    DataSource = DataSource1
    TabOrder = 6
  end
  object DBMemo1: TDBMemo
    Left = 207
    Top = 259
    Width = 185
    Height = 74
    DataField = 'AMemo'
    DataSource = DataSource1
    TabOrder = 7
  end
  object DBEdit1: TDBEdit
    Left = 24
    Top = 264
    Width = 121
    Height = 21
    DataField = 'AName'
    DataSource = DataSource1
    TabOrder = 8
  end
  object SQLConnection1: TSQLConnection
    ConnectionName = 'SQLITECONNECTION'
    DriverName = 'Sqlite'
    LoginPrompt = False
    Params.Strings = (
      'DriverName=Sqlite'
      'Database=D:\delphi\xe6\sqlite\matestdb.sqlite')
    Connected = True
    Left = 40
    Top = 16
  end
  object SQLQuery1: TSQLQuery
    MaxBlobSize = 1
    Params = <>
    SQL.Strings = (
      'select * from [matable2]')
    SQLConnection = SQLConnection1
    Left = 128
    Top = 16
    object SQLQuery1ID: TLargeintField
      FieldName = 'ID'
      ProviderFlags = [pfInWhere, pfInKey]
    end
    object SQLQuery1AName: TWideStringField
      FieldName = 'AName'
    end
    object SQLQuery1AMemo: TWideMemoField
      FieldName = 'AMemo'
      BlobType = ftWideMemo
      Size = 1
    end
  end
  object DataSetProvider1: TDataSetProvider
    DataSet = SQLQuery1
    Options = [poAllowCommandText, poUseQuoteChar]
    UpdateMode = upWhereKeyOnly
    Left = 216
    Top = 16
  end
  object CDS1: TClientDataSet
    Aggregates = <>
    CommandText = 'select * from MATable2'
    Params = <>
    ProviderName = 'DataSetProvider1'
    BeforeInsert = CDS1BeforeInsert
    AfterInsert = CDS1AfterInsert
    BeforePost = CDS1BeforePost
    AfterPost = CDS1AfterPost
    AfterDelete = CDS1AfterDelete
    OnNewRecord = CDS1NewRecord
    AfterApplyUpdates = CDS1AfterApplyUpdates
    Left = 288
    Top = 16
    object CDS1ID: TLargeintField
      FieldName = 'ID'
    end
    object CDS1AName: TWideStringField
      FieldName = 'AName'
    end
    object CDS1AMemo: TWideMemoField
      FieldName = 'AMemo'
      BlobType = ftWideMemo
      Size = 1
    end
  end
  object DataSource1: TDataSource
    DataSet = CDS1
    Left = 344
    Top = 16
  end
end
person MartynA    schedule 21.07.2014
comment
Не уверен, что правильно вас понял... Я не выбираю, а выполняю своего рода запрос на вставку. - person user763539; 22.07.2014
comment
Это довольно необычная вещь. Если бы я хотел сделать такую ​​вставку, я бы использовал 'SELECT * from MY_TABLE WHERE 1=2', а остальное оставил CDS + ее провайдеру. Попробуй это. Кстати, вы не пытаетесь вставить более одного значения столбца в параметр A, не так ли? Я не был совсем уверен, означает ли слово «twit» имя столбца или что-то в этом роде. - person MartynA; 22.07.2014
comment
на самом деле я собирался вставить больше значений, но я просто сделал одно для начала, чтобы посмотреть, работает ли оно. twit — это поле в моей базе данных (памятка). Как именно вы вставляете в таблицу, которая находится на стороне сервера от клиента? - person user763539; 22.07.2014
comment
Я бы использовал фиктивный оператор SELECT, подобный тому, который я предложил, - таким образом поставщик + CDS может получить столько метаданных, сколько возможно, а затем просто .Open CDS. Он начнется с нулевых строк, но ему все равно. Я бы не ожидал, что попытка вставить строку только с полем Memo будет работать, независимо от того, используется ли CDS или нет - наборы данных (Delphi) ничего не могут использовать в качестве ключа. Но могу ошибаться в этом... - person MartynA; 22.07.2014
comment
@ user763539: У вас есть какие-то успехи в этом или все еще застряли? - person MartynA; 23.07.2014
comment
@ MartynA - нет, марти, извините .... все примеры учат вас, как построить сервер привязки данных, но не из них, как вставлять данные. Кажется, мне не хватает фундаментального принципа функционирования этой вещи (вставка). Итак, скажите, пожалуйста, как вы на самом деле вставляете данные? Мой набор данных связан с поставщиком данных (таблица на сервере), поэтому простой запрос (вот почему я делаю одну вставку) из набора данных клиента должен работать. Или я что-то упускаю? Delphi — это XE6 с использованием DBX. - person user763539; 24.07.2014
comment
Хотя столбец ID на сервере определен как Autoinc, получить значение autoinc при выполнении вставки CDS проблематично, - я заметил это. Спасибо. - person user763539; 27.07.2014