Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Базы данных и репортинг > TADOQuery - не получаеться выполнить запрос


Автор: KgCoder 11.9.2010, 15:29
Код

  with ADOQueryDB do
  try
    Close;
    SQL.Add('DELETE * FROM Diagnose WHERE ID = '+ IntToStr(ID) +' OR ParentID = '+ IntToStr(ID));
    ExecSQL;
  finally
    ShowMessage('Node #'+ IntToStr(ID) +' deleted from database.');
  end;


Пишет: ADOQueryDB: Cannot perform this operation on a closed dataset.

Подскажите ошибку...  smile 

Автор: KgCoder 11.9.2010, 17:01
Нашел это: http://www.delphisources.ru/forum/showpost.php?p=38111&postcount=13

Сделал так:
Код

  with ADOQueryDB do
  try
    Active := false;
    DataSource.Enabled := false;
    tmp_query := SQL.Text;
    SQL.Text := 'DELETE * FROM Diagnose WHERE ID = '+ IntToStr(ID) +' OR ParentID = '+ IntToStr(ID);
    ExecSQL;
  finally
    SQL.Text := tmp_query;
    Active := true;
    DataSource.Enabled := true;
    ShowMessage('Node #'+ IntToStr(ID) +' deleted from database.');
  end;


Теперь она выводит ошибку "Access violation"... 

Автор: БелАмор 11.9.2010, 20:22
По поводу первого варианта

Вы добавляете строку к тому, что уже было в свойстве SQL. И что получается?
Либо перед добавлением очищайте свойство SQL, либо присвавайте напрямую SQL.Text
Свойство SQL имеет тип TStrings. Почитайте о TStrings, он используется практически везде.

По поводу второго варианта

1. "Active := false" и "Close" - это одно и то-же.
2.  "DataSource.Enabled := false"
    а) А у вас вообще назначено свойство ADOQueryDB.DataSource ?
    б) Если назначено, то зачем?  
3.
Цитата

tmp_query := SQL.Text;
...
SQL.Text := tmp_query;

Если в ADOQueryDB могут выполняться разные запросы, то формируйте их все каждый раз заново, не интересуясь, что там было в свойстве SQL раньше, а не занимайтесь сохранением/восстановлением чего-то, забитого в дизайн-тайм.
4.
Цитата

Active := true;

Active:=True или Open используются для запросов, возвращающих данные, т.е. для запросов с SELECT

Автор: KgCoder 12.9.2010, 00:37
Цитата(БелАмор @  11.9.2010,  20:22 Найти цитируемый пост)
Вы добавляете строку к тому, что уже было в свойстве SQL. И что получается?Либо перед добавлением очищайте свойство SQL, либо присвавайте напрямую SQL.TextСвойство SQL имеет тип TStrings. Почитайте о TStrings, он используется практически везде.

ADOQuery чист. Тем не менее, ошибка выходит и через SQL.Text и через SQL.Clear; SQL.Add;

Цитата(БелАмор @  11.9.2010,  20:22 Найти цитируемый пост)
1. "Active := false" и "Close" - это одно и то-же.2.  "DataSource.Enabled := false"    а) А у вас вообще назначено свойство ADOQueryDB.DataSource ?    б) Если назначено, то зачем?  3.Цитатаtmp_query := SQL.Text;...SQL.Text := tmp_query;Если в ADOQueryDB могут выполняться разные запросы, то формируйте их все каждый раз заново, не интересуясь, что там было в свойстве SQL раньше, а не занимайтесь сохранением/восстановлением чего-то, забитого в дизайн-тайм.4.ЦитатаActive := true;Active:=True или Open используются для запросов, возвращающих данные, т.е. для запросов с SELECT

Всё это я знаю, и всё это взято из примера указанного по ссылке и не изменено, чтобы подчеркнуть тот, что проблему там решили, а в моём случае, она не решается.

Ориентируйтесь на первый пост. Там нету ничего лишнего и при этом она провоцирует ошибку.

Прикрепляю файл проекта. (Используются ADO, PNGComponents и VirtualTree).

Автор: Данкинг 12.9.2010, 01:04
Код

with ADOQueryDB do
 begin
    Close;
    SQL.Clear;
    SQL.Text := 'DELETE * FROM Diagnose WHERE ID = '+ IntToStr(ID) +' OR ParentID = '+ IntToStr(ID);
    ExecSQL;
    ShowMessage('Node #'+ IntToStr(ID) +' deleted from database.');
  end;

Автор: cat512 12.9.2010, 17:06
Цитата(KgCoder @ 11.9.2010,  15:29)
Код

  with ADOQueryDB do
  try
    Close;
    SQL.Add('DELETE * FROM Diagnose WHERE ID = '+ IntToStr(ID) +' OR ParentID = '+ IntToStr(ID));
    ExecSQL;
  finally
    ShowMessage('Node #'+ IntToStr(ID) +' deleted from database.');
  end;


Пишет: ADOQueryDB: Cannot perform this operation on a closed dataset.

Подскажите ошибку...  smile

Может проблема в запросе? Что там за звёздочка такая? 

Автор: Данкинг 12.9.2010, 18:11
Цитата(cat512 @  12.9.2010,  18:06 Найти цитируемый пост)
Может проблема в запросе? Что там за звёздочка такая?  

Вообще действительно: зачем звёздочка в delete? Хотя из-за этого должны быть глюки запроса, а не "closed dataset".

Автор: БелАмор 12.9.2010, 20:31
Цитата(KgCoder @  12.9.2010,  00:37 Найти цитируемый пост)
ADOQuery чист.

Это не так. Вот здесь вы заполняете SQL:
Код

procedure TFormApplication.ListBoxInformationLoadDB(Node: PVirtualNode);
var
  Data: PDiagnose;
begin
  ListBoxInformation.Clear;
  Data := VirtualStringTreeDB.GetNodeData(Node);
  with ADOQueryDB do
  try
    Close;
    SQL.Text := 'SELECT * FROM '+ FocusedRichEdit +' WHERE DiagnoseID = '+ IntToStr(Data.ID);
    Open;
  finally
    First;
    while not Eof do
    begin
      ListBoxInformation.Items.Add(FieldByName('Content').AsString);
      Next;
    end;
  end;
end;

Кстати, здесь try-finally используется не по делу: вы пытаетесь работать с данными в любом случае, даже если при выполнении запрроса произошло исключение...
Цитата(KgCoder @  12.9.2010,  00:37 Найти цитируемый пост)
Тем не менее, ошибка выходит и через SQL.Text и через SQL.Clear; SQL.Add;

Тогда не знаю...

Автор: KgCoder 12.9.2010, 22:14
Проблему решил!!!  smile 

Проблема заключалось в... не знаю в чём. В общем вот код процедур загрузки/создания/редактирования/удаления:
Код

procedure TFormApplication.VirtualStringTreeDBLoadDiagnose(Node: PVirtualNode;
  Data: PDiagnose);
begin
  with TADOQuery.Create(nil) do
  try
    Connection := ADOConnectionDB;
    SQL.Text := 'SELECT * FROM Diagnose WHERE ParentID = '+ IntToStr(Data.ParentID) +' AND Content ="'+ Data.Content +'"';
    Open;
    First;
  finally
    Data := VirtualStringTreeDB.GetNodeData(Node);
    Data^.ID := FieldByName('ID').AsInteger;
    Data^.ParentID := FieldByName('ParentID').AsInteger;
    Data^.Content := FieldByName('Content').AsString;
    Free;
  end;
end;

procedure TFormApplication.VirtualStringTreeDBCreateDiagnose(Node: PVirtualNode;
  Data: PDiagnose; NewText: WideString);
var
  ParentData: PDiagnose;
  ParentID: Integer;
begin
  with VirtualStringTreeDB do
  begin
    ParentData := GetNodeData(Node.Parent);
    if (SelectedCount > 0) then
      ParentID := ParentData.ID
    else
      ParentID := 0;
  end;
  with TADOQuery.Create(nil) do
  try
    Connection := ADOConnectionDB;
    SQL.Text := 'INSERT INTO Diagnose (ParentID, Content) VALUES ('+ IntToStr(ParentID) +', "'+ NewText +'")';
    ExecSQL;
  finally
    Data^.ID := 0;
    Data^.ParentID := ParentID;
    Data^.Content := NewText;
    VirtualStringTreeDBLoadDiagnose(Node, Data);
    Free;
  end;
end;

procedure TFormApplication.VirtualStringTreeDBUpdateDiagnose(Node: PVirtualNode;
  Data: PDiagnose; NewText: WideString);
begin
  with TADOQuery.Create(nil) do
  try
    Connection := ADOConnectionDB;
    SQL.Text := 'UPDATE Diagnose SET Content = "'+ NewText +'" WHERE ID = '+ IntToStr(Data.ID);
    ExecSQL;
  finally
    Data^.Content := NewText;
    Free;
  end;
end;

procedure TFormApplication.VirtualStringTreeDBDeleteDiagnose(Node: PVirtualNode;
  Data: PDiagnose);
begin
  with TADOQuery.Create(nil) do
  try
    Connection := ADOConnectionDB;
    SQL.Text := 'DELETE * FROM Diagnose WHERE ID = '+ IntToStr(Data.ID);
    ExecSQL;
  finally
    Free;
  end;
end;


То есть теперь ADOConnection создаётся при FormCreate, а ADOQuery отдельно для каждого действия. Теперь ругайте... может нагрузка больщая? Или чего не правильно?  smile 

Автор: БелАмор 13.9.2010, 22:42
Цитата(KgCoder @  12.9.2010,  22:14 Найти цитируемый пост)
То есть теперь ADOConnection создаётся при FormCreate, а ADOQuery отдельно для каждого действия. Теперь ругайте... 

Вполне нормальный подход. Ничего особо плохого в нём нет. Даже есть плюсы, в частности, привычка писать программу кодом...
Хотел бы только обратить внимание несколько моментов:
1. После открытия датасета (который до этого был в закрытом состоянии) текущей записью всегда становится первая, поэтому вызывать First в этом случае излишне.
2. Вообще, сложные строки удобно формировать с помощью функции Format. Это гораздо нагляднее, чем куча плюсов с апострофами, вызовами IntToStr и подобного. Я имею в виду действительно сложные строки, в данном случае это не очень актуально.
3. Данные, текстовое представление которых зависит от региональных настроек (например, дата), передавайте в запрос только через параметры. В данном случае таких данных не наблюдается, но наблюдается стремление писать весь запрос текстом...
4. Таки уберите уж звёздочку между DELETE и FROM... 

Автор: Deniz 14.9.2010, 05:23
Цитата(KgCoder @  13.9.2010,  00:14 Найти цитируемый пост)
Теперь ругайте.
Ну если уж сам просишь, извольте.
Первым делом посмотри как работает блок try finally end.
Далее, про Open + First уже сказали, First не нужен.
Все тексты запросов к БД лучше оформлять с параметрами.
Зачем в каждой процедуре создавать и удалять ADOQuery? Можно одну кинуть на форму и с ней работать.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)