Обновление данных в MS SQL

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Обновление данных в MS SQL

Сообщение alterspirt » 10.09.2014 19:45:54

Всем привет.

С програмирование знаком мало, в основном ковырял Power Shell, но тут повилась задача, требующая графической части и простоты в работе. Решил попробовать Lazarus.

Цель:

Сделать небольшую оболочку, в которой мы задаем настройки подключения к MS SQL серверу и указываем несколько переменных, которые используются в динамическом запросе. Полученные результаты выводятся на экран, мы подправляем нужные нам строки и сохраняем результат в базу. За два дня более менее понял что к чему, посмотрел некоторые видео, получилась вот такая форма:

Изображение

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

Изображение

Проблема:

Застрял на этапе обновления, на скрине выше видно, что нужное мне значение меняется, но как только я нажимаю обновить, мне пишут вот такую ошибку:

Изображение

Подскажите, как корректно апдейтить сделанные изменения в базу?

Сам код приложения:

Код: Выделить всё

unit MainForm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus,
  StdCtrls, DBGrids, DbCtrls, DBSettingsForm, mssqlconn, sqldb, db;

type

  { TMForm }

  TMForm = class(TForm)
    Amount: TLabel;
    UpdSQL: TButton;
    AmountEdit: TDBEdit;
    DBNavigator1: TDBNavigator;
    DBHotelText: TDBText;
    DBRoomText: TDBText;
    SQLQuerySample: TEdit;
    EndDateSQLQuery: TEdit;
    EndDate: TLabel;
    Button1: TButton;
    DBGrid1: TDBGrid;
    BegDate: TLabel;
    AmountSQLQuery: TEdit;
    BeginDateSQLQuery: TEdit;
    QueryResult: TDataSource;
    DisconnectButton: TButton;
    ConStat: TLabel;
    MainMenu: TMainMenu;
    MAbout: TMenuItem;
    MDBSettings: TMenuItem;
    MExit: TMenuItem;
    MOptions: TMenuItem;
    MHelp: TMenuItem;
    MFile: TMenuItem;
    TVDBTransaction: TSQLTransaction;
    TVDBQuery: TSQLQuery;
    TVDBConnection: TMSSQLConnection;
    procedure Button1Click(Sender: TObject);
    procedure DisconnectButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure MExitClick(Sender: TObject);
    procedure MDBSettingsClick(Sender: TObject);
    procedure QueryResultDataChange(Sender: TObject; Field: TField);
    procedure QueryResultUpdateData(Sender: TObject);
    procedure UpdSQLClick(Sender: TObject);



  private
    { private declarations }
  public
    { public declarations }
  end;

var
  MForm: TMForm;

implementation

{$R *.lfm}

{ TMForm }

procedure TMForm.MExitClick(Sender: TObject);
begin
  Close;
end;

procedure TMForm.MDBSettingsClick(Sender: TObject);
begin
  DBSForm.Show;
end;

procedure TMForm.QueryResultDataChange(Sender: TObject; Field: TField);
begin

end;

procedure TMForm.QueryResultUpdateData(Sender: TObject);
begin

end;

procedure TMForm.UpdSQLClick(Sender: TObject);
begin
   TVDBQuery.UpdateSQL.Clear;
   TVDBQuery.UpdateSQL.Text:='Update HotelAllotRoom SET Ammount = '+ AmountEdit.DataField + ' where Hotel = "'+DBHotelText.DataField+'"' ;
   SQLQuerySample.Text:=TVDBQuery.UpdateSQL.Text


end;


procedure TMForm.FormCreate(Sender: TObject);
begin




end;

procedure TMForm.Button1Click(Sender: TObject);
begin
  If TVDBConnection.Connected = False then
  begin
    TVDBConnection.DatabaseName:=DBSForm.DBName.Text;
    TVDBConnection.HostName:=DBSForm.ServName.Text;
    TVDBConnection.UserName:=DBSForm.UserName.Text;
    TVDBConnection.Password:=DBSForm.Password.Text;

    if TVDBConnection.DatabaseName='' then
    begin
       showmessage('Please fill Database Name in Options -> DB Settings');
    end;

    if TVDBConnection.HostName='' then
    begin
       showmessage('Please fill Server Address in Options -> DB Settings');
    end;

    if not DBSForm.EmptyUserName.Checked then
    begin
    if TVDBConnection.UserName='' then
    begin
       showmessage('Please fill User Name in Options -> DB Settings');
    end;
    end;

    if not DBSForm.EmptyPassword.Checked then
    begin
    if TVDBConnection.Password = '' then
    begin
       showmessage('Please fill User Password in Options -> DB Settings');
    end;
    end;

    try

      TVDBConnection.Connected:=True;
      ConStat.caption:='Connected!!';

      TVDBQuery.Close;
      TVDBQuery.SQL.Text:='SELECT Hotel, Room, Date, Amount from HotelAllotRoom WHERE Date > '''+ BeginDateSQLQuery.Text + ''' and Date < ''' + EndDateSQLQuery.Text +''' and Amount < ' + AmountSQLQuery.Text;
      TVDBQuery.Open;
      SQLQuerySample.Text:=TVDBQuery.SQL.Text;

    except
    on E: Exception do
    begin
    showmessage('Error connecting to database. Technical details: '+E.ClassName+'/'+E.Message);
    end;

      end;
  end;

end;



procedure TMForm.DisconnectButtonClick(Sender: TObject);
begin
  if TVDBConnection.Connected = True then
  try
      TVDBConnection.Connected:=False;
      ConStat.caption:='Disconected :(';
  finally
  end;
end;

end.



Так как это проба пера, все действия завязаны на кнопку Connect, код повешанный на UpdSQLClick можно игнорировать, это неуспешные попытки.

Доп. вопрос:

Можно ли обойтись без дополнительных кнопок и автоматически апдейтить поля, измененные в DBGrid?

Любые комментарии /критика /замечания приветствуются.

Спасибо.
alterspirt
незнакомец
 
Сообщения: 5
Зарегистрирован: 10.09.2014 18:37:35

Re: Обновление данных в MS SQL

Сообщение Ism » 10.09.2014 20:18:01

Обновление должно быть по уникальному ключу, а вы обновляете сразу несколько записей
Да и с updatesql не так делается

Добавлено спустя 11 минут 12 секунд:
Содержание updatesql
Update Table set amount=:amount where id=:id

Добавлено спустя 3 минуты 10 секунд:
SQLQuery.applyupdates
Transaction.commit
Ism
энтузиаст
 
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Re: Обновление данных в MS SQL

Сообщение alterspirt » 11.09.2014 11:16:57

Ism,

спасибо, что откликнулись, но пока просветление не достигнуто, расшифруйте пожалуйста подробнее ваши рекомендации?

Как я их понял, нужно править блок TMForm.UpdSQLClick, что мы делаем по нажатию кнопки Update.

Я попробовал привести вот к такому виду:

procedure TMForm.UpdSQLClick(Sender: TObject);
begin
TVDBQuery.UpdateSQL.Text:='Update HotelAllotRoom set amount=:amount where id=:id;';
TVDBQuery.ApplyUpdates;
TVDBTransaction.Commit;

end;
При таком раскладе мне ругаются что Apperation can not be perfomed on Active Data Set.

Но если я добавляю TVDBQuery.Close; то у меня пропадают все данные с экрана, что в общем то логично...

Может моя ошибка в том, что данные отображаются сразу в DBGrid? Может правильно делать запрос, сохранять его результаты в переменную, переменную выводить через DBGrid на экран, править ее и потом обновлять уже?
alterspirt
незнакомец
 
Сообщения: 5
Зарегистрирован: 10.09.2014 18:37:35

Re: Обновление данных в MS SQL

Сообщение Ism » 11.09.2014 13:16:36

Запросы, которые я указал вписываются во время дизайна
После компиляции обьект вызывает их сам, обработка событий не требуется
То есть после редактирования вам нужно только подтвердить отправку записей
SQLQuery.applyupdates
Transaction.commit
Ism
энтузиаст
 
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Re: Обновление данных в MS SQL

Сообщение alterspirt » 12.09.2014 10:04:08

Ism, спасибо большое, все получилось. Решил таким способом:

Код: Выделить всё

// Создаем процедуру

procedure SaveChanges;

//описываем ее

procedure TForm1.SaveChanges;
begin
  try
    if SQLTransaction1.Active then
   
    begin
      SQLQuery1.ApplyUpdates; //Применяем обновления
      SQLTransaction1.Commit; //... и комитим их
      //SQLTransaction1.Active переходит в False
    end;
  except
  on E: EDatabaseError do
    begin
      MessageDlg('', 'A database error has occurred. Technical error message: ' +
        E.Message, mtError, [mbOK], 0);
      Edit1.Text := '';
    end;
end;

//действия по нажатию кнопки Save

procedure TForm1.SaveClick(Sender: TObject);
begin
  SaveChanges; //Сохраняем изменения и комитим транзакции
  SQLQuery1.Close; //Закрываем запрос
  SQLTransaction1.Active := False; //Закрываем транзакцию
  DBConnection.Connected := False; // Отключаемся от базы
end; 
                 


Указание SQLQuery1.UpdateSQL.Text:= 'Update ResMain SET ResNote=:ResNote, Agency=:Agency WHERE ResNo=:ResNo'; не потребовалось, но есть вот какая проблема, может сталкивались:

Update в большинство таблиц проходит, а в нужные мне нет. Причем в SQL Profiler виден запрос и он корректен, если его скопировать и выполнить на самом скуле, данные обновляются, ругань идет со стороны Lazarus, ругань вот такого вида:

Изображение

Ошибка возникает на этапе:

Код: Выделить всё
SQLQuery1.ApplyUpdates;


После нее SQL раскорячивает и преходится его перезагружать (созданный из Lazarus коннект к SQL блокирует LCK_M_S что не дает проходить другим запросам)

Что пробовал:

Игрался с полем SQLQuery1.UpdateSQL.Text:= пытался предавать все данные из строки, передавал только часть как на примере выше, ошибка в любом случае, но разное их количество, т.е на принтскрине ошибка в случае запроса вида 'Update ResMain SET ResNote=:ResNote, Agency=:Agency WHERE ResNo=:ResNo' если передаем все параметры больше строчек с руганью на Incorrect Syntax

Пробовал задавать SQLQuery1.UpdateMode, те же грабли.

Со стороны SQL в логах тишина, хотя вроде как рекомендует проверять как раз их. Единственное отличие этой таблицы от других, в ней есть индексы. Но это так, пальцем в небо.

Интуитивно кажется что Lazarus как то не корректно передает запросы в SQL по этой таблице, что вызывает ошибку, с другой стороны, эти запросы напрямую отрабатываются в SQL корректно.

Спасибо за идеи.


Из PowerShell попробовал, запрос отрабатывает мгновенно без ошибок. Может что-то не так в dll? Я использую dblib.dll от 28.05.2014 и libiconv2.dll 1.9.2.1747

UPD:

В PS коннект к базе идет через вот такой код, может можно и из Lazarus ломиться напрямую?
Код PS

Код: Выделить всё

$SqlServer = "SERVER"
$SqlCatalog = "DATABASE"
$SqlUser = 'USER'
$SqlQuery = "Update ResMain SET ResNote=N'TEST', Agency=N'IDROZOVO' WHERE ResNo=N'01173787'"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SqlServer; Database = $SqlCatalog; Integrated Security = False; User = $SqlUser"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$result = $SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
return $DataSet.Tables[0]



UPD2:

На данной таблице есть тригер, после его выключения, Update заработал. Есть какие то нюансы при Update с Trigger?

Добавлено спустя 2 часа 59 минут 36 секунд:
В общем переделал подключение через компонент TODBCConnection все заработало и апдейты пошли.

Код: Выделить всё

procedure TForm1.ConnectButtonClick(Sender: TObject);
begin
  //SaveChanges; //Saves changes and commits transaction
  try
  //SQLQuery1.Close;
  //Connection settings for Firebird/Interbase database
  //only needed when we have not yet connected:
  if not SQLODBC.Connected then
  begin
    SQLODBC.Driver:='SQL Server';
    SQLODBC.Params.Add('Server=' + ServerName.Text);
    SQLODBC.Params.Add('Database=' + DatabaseName.Text);
    SQLODBC.Params.Add('Trusted_Connection=Yes');
    SQLODBC.Params.Add('User=' + UserName.Text);

    // Now we've set up our connection, visually show that
    // changes are not possibly any more
    ServerName.ReadOnly:=true;
    DatabaseName.ReadOnly:=true;
    UserName.ReadOnly:=true;
    Password.ReadOnly:=true;
  end;
  SQLQuery1.SQL.Text:= 'SELECT top 10 * from ResMain';
  SQLODBC.Connected:= True;
  SQLTransaction1.Active:= True;
  SQLQuery1.Open;

  except
    //We could use EDatabaseError which is a general database error, but we're dealing with Firebird/Interbase, so:
    on E: EDatabaseError do
    begin
      MessageDlg('Error','A database error has occurred. Technical error message: ' + E.Message,mtError,[mbOK],0);
      Edit1.Text:='';
    end;
  end;
end;                   

alterspirt
незнакомец
 
Сообщения: 5
Зарегистрирован: 10.09.2014 18:37:35

Re: Обновление данных в MS SQL

Сообщение Ism » 12.09.2014 13:42:05

Возможно версия клиентской библиотеки не соответствует серверу
Или компонент не доделан, ms sql штука закрытая
Ism
энтузиаст
 
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 247

Рейтинг@Mail.ru
cron