Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2008.04.06;
Скачать: [xml.tar.bz2];

Вниз

Кто как поступает?   Найти похожие ветки 

 
zorik ©   (2007-11-09 12:09) [0]

САБЖ. Есть грид. Данные берет с запроса TIBSQL. Запрос только для чтения. Есть кнопки "добавить", "изменить", "удалить". Для редактирования используется второй запрос, куда параметрически передается первичный ключ с первого. При нажатии на кнопку передаем ключ во второй запрос, откриваем модальное окно с dbcontrol-ами, связаными с вторым запросом, что используется для редактирования. При нажатии на ок выпольняется update и подтверждается транзакция. Все отлично работает, но после изменения данных, надо перечитать первый запрос, чтоб увидеть эти изменения. При этом курсор переходит на первую запись. Это не удобно. Я использовал Locate после переоткрытия запроса, но при большом количестве записей это сильно тормозит. Да и выделенная строка грида оказывается в самом низу видимой части грида.

Подскажите какие есть варианты решения?


 
Desdechado ©   (2007-11-09 12:13) [1]

Использовать кэшированные изменения, например, с ClientDataSet.


 
Reindeer Moss Eater ©   (2007-11-09 12:13) [2]

bookmark вместо locate


 
Ega23 ©   (2007-11-09 12:21) [3]


> bookmark вместо locate


нельзя, у него запись может добавиться.


 
ЮЮ ©   (2007-11-09 12:22) [4]

> Есть грид. Данные берет с запроса TIBSQL


Как то сомнительно. Или справка Врет?
Description

Use a TIBSQL object to execute an InterBase SQL statement with minimal overhead.  TIBSQL has no standard interface to data-aware controls and is unidirectional.


> Для редактирования используется второй запрос, куда параметрически
> передается первичный ключ с первого.


А посему просто не использовать TIBDataSet и его методы Insert, Post, Delete. Т.е. изменять данные "в гриде" и слать соответствующие запросы на сервер, а не наоборот?


 
Reindeer Moss Eater ©   (2007-11-09 12:24) [5]

нельзя, у него запись может добавиться.

В делфи для этого есть опертор if


 
Ega23 ©   (2007-11-09 12:35) [6]

По сабжу.
Обычно делаю так:
есть форма, на ней вся выборка. Есть три Action"а: Add, Edit, Delete.
Есть модальная форма, вызывается для добавления записи или изменения записи.
выгдядит приблизительно так:

type
 TRecordEditForm = class(TForm)
 private
   FWorkMode : Integer;
   procedure  SetFWorkMode(const Value : Integer);
   procedure btnOKClick(Sender : TObject); // реакция на кнопку OK
 public
   property WorkMode : Integer read FWorkMode write SetFWorkMode;  // 0 - добавляем, 1 - изменяем;
   property ID : Integer read FID write FID; // Название ключевого поля
   // ещё я, обычно, сюда коннект к БД добавляю, дабы не плодить дополнительных
 // хотя если ты DataModule используешь - но не нужно
 end;

procedure TRecordEditForm.SetFWorkMode(const Value : Integer);
begin
 FWorkMode := Value;

 if Value=0
 begin // Добавление записи
    // заполняем контролы default-значениями
 end;

 if Value=1
 begin // Изменение записи
    "select * from ... where ID=" + IntToStr(FID);
    выполняем вспомогательный запрос, заполняем все контролы данными из этого запроса
 end;

end;

procedure TRecordEditForm.btnOKClick(Sender : TObject); // реакция на кнопку
OK
var
 ss : string;
begin
 case WorkMode of
   0 : ss := "Добавить запись?";
   1 : ss := "Изменить запись?";
 end;

 if not (MessageBox(Handle, PChar(ss), PChar("Внимание!"),
                           MB_OKCANCEL or MB_ICONINFORMATION)=IDOK) then Exit;
// дальше формируем строку на добавление или изменение записи, в зависимости от WorkMode
 // Выполняем обновление.
 // Запрос строю таким образом, чтобы при добавлении новой записи мне вернулось значение её ключевого поля.
 // Записываем это значение в FID;

 Modalresult := mrOK;

end;


 
Ega23 ©   (2007-11-09 12:39) [7]

соответственно, вызов этого дела из Action"ов:


procedure TMainForm.afAddRecordExecute(Sender: TObject);
begin
 Application.CreateForm(TRecordEditForm, RecordEditForm);
 try
   RecordEditForm.workMode := 0;
   RecordEditForm.ShowModal;
   if RecordEditForm.ModalResult<>mrOK then Exit;
   RefreshData; // обновляем данные основного запроса
   DataSet.Locate("ID", RecordEditForm.ID, []) ;
 finally
   TRecordEditForm.Free;
 end;
end;

procedure TMainForm.afEditRecordExecute(Sender: TObject);
begin
 Application.CreateForm(TRecordEditForm, RecordEditForm);
 try
   RecordEditForm.workMode := 1;
   RecordEditForm.ID := DataSet.FieldByName("ID").AsInteger;
   RecordEditForm.ShowModal;
   if RecordEditForm.ModalResult<>mrOK then Exit;
   RefreshData; // обновляем данные основного запроса
   DataSet.Locate("ID", RecordEditForm.ID, []) ;
 finally
   TRecordEditForm.Free;
 end;
end;



 
Ega23 ©   (2007-11-09 12:41) [8]

Это - общий шаблон.
Да, вот ещё: в модальной форме не использую DB-контролов (кроме DBLookupCombo, если что-то из справочной таблицы выбрать надо). предпочитаю обычные Edit, dateTimePicker, Memo и ComboBox. В 95% случаев их достаточно.


 
ЮЮ ©   (2007-11-09 12:42) [9]

> есть форма, на ней вся выборка.


if RecordEditForm.Modalresult = mrOK then

м что делаешь тут, чтобы вся выборка обновилась?


 
Reindeer Moss Eater ©   (2007-11-09 12:43) [10]

дело вкуса, но вообще сильно горбатый шаблон.
сплошной копипаст.


 
Ega23 ©   (2007-11-09 12:44) [11]

if RecordEditForm.ModalResult<>mrOK then Exit;

Соответственно, в случае mrOK выполнится RefreshData


 
Ega23 ©   (2007-11-09 12:45) [12]


> сплошной копипаст.


Шаблон формы - в репозитории.


 
Ega23 ©   (2007-11-09 12:46) [13]


> но вообще сильно горбатый шаблон.


Возможно. Просто не хотел делать по 2 модальные формы для добавления и редактирования. Как-то один раз такой механизм разработал - и уже 6 лет им пользуюсь.
Лично меня не напрягает.


 
Reindeer Moss Eater ©   (2007-11-09 12:47) [14]

Я про то, что во многих местах повторяется один и тот же код.
Создание, инициализация экземпляря формы редактирования, вызов её методов и т.д.


 
Ega23 ©   (2007-11-09 12:49) [15]


> Я про то, что во многих местах повторяется один и тот же
> код.
> Создание, инициализация экземпляря формы редактирования,
>  вызов её методов и т.д.
>


Ты знаешь, меня в-общем-то это тоже поначалу напрягало. Но придумать красивый шаблон, с учётом того, что, как правило, в RefreshData может дохрена чего происходить (это я в примере так написал, реально код в 60% случаев - разный) я придумать так и не смог.
В конце-концов плюнул на всё слюной и оставил как есть.


 
Reindeer Moss Eater ©   (2007-11-09 12:53) [16]

у меня этот код всегда выносится в неклассовую функцию в модуле формы редактирования, а вызовы аппенд и эдит выглядят как

If DoEdit(-1) then //Для новой записи
If DoEdit(<ключ>) then //Для редактирования существующей.

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


 
Desdechado ©   (2007-11-09 12:55) [17]

> Reindeer Moss Eater ©   (09.11.07 12:13) [2]
> bookmark вместо locate
Bookmark - это указатель на запись в ТЕКУЩЕМ состоянии датасета. При переоткрытии указатель становится инвалидным, т.к. указатель может быть совсем в никуда или непонятно на что.


 
Reindeer Moss Eater ©   (2007-11-09 13:03) [18]

ну так есть же методы проверки букмарка на валидность


 
Reindeer Moss Eater ©   (2007-11-09 13:05) [19]

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


 
Sergey13 ©   (2007-11-09 13:08) [20]

> [4] ЮЮ ©   (09.11.07 12:22)
> Т.е. изменять данные "в гриде"

Причем можно и не "в гриде", а как у автора в модальных формах.


 
Ega23 ©   (2007-11-09 13:11) [21]


> ну так есть же методы проверки букмарка на валидность


Откровенно говоря, я так не рискую.


 
ЮЮ ©   (2007-11-09 13:15) [22]

> Причем можно и не "в гриде", а как у автора в модальных
> формах.

Естественно. Но я не об этом. Я имел ввиду изменять данные в DataSete, отображаемом в качестве "всей выборки", где посылка запросов на сервер - "побочный эффект" таких изменений.

Единственно, при многопользовательском режиме захочется получить во "всей выборке" и изменения, сделанные другими. Вариант полного обновления "всей выборки" по завершении редактирования как-то выполняет эту работу, не заставляя его каждый раз жать "обновить".


 
Reindeer Moss Eater ©   (2007-11-09 13:16) [23]

Фигня какая. Валидный букмарк - пробуем перейти.
Получилось - хорошо, не получилось - в следующий раз получится.


 
Ega23 ©   (2007-11-09 13:22) [24]


> Фигня какая. Валидный букмарк - пробуем перейти.
> Получилось - хорошо, не получилось - в следующий раз получится.


ИМХО, дело вкуса, стиля и привычки.


 
Anatoly Podgoretsky ©   (2007-11-09 13:25) [25]

Функцию режима с успехом может выполнять ID, особенно если это автоинкриментное поле. Предложено выше.


 
Sergey13 ©   (2007-11-09 13:29) [26]

> [22] ЮЮ ©   (09.11.07 13:15)
> Я имел ввиду

Да я понял. Вообще, ИМХО, просто автор поддался на страшилки противников "редактирования в гриде". 8-)

> захочется получить во "всей выборке" и изменения, сделанные другими.
А такие попытки надо пресекать в зародыше - нефиг за другими подглядывать. 8-)


 
Desdechado ©   (2007-11-09 13:31) [27]

> Фигня какая. Валидный букмарк - пробуем перейти.Получилось
> - хорошо, не получилось - в следующий раз получится.
А теперь представь: было у тебя в датасете 30 записей. Стало 35, но 28 из них - другие. Даже при валидном букмарке (что сомнительно) ты перейдешь непонятно на что, т.к. в этой области памяти расположилась уже какая-то новая строка.
И нафига такая "помощь" пользователю?


 
Reindeer Moss Eater ©   (2007-11-09 13:43) [28]

А теперь представь: было у тебя в датасете 30 записей. Стало 35, но 28 из них - другие. Даже при валидном букмарке (что сомнительно) ты перейдешь непонятно на что, т.к. в этой области памяти расположилась уже какая-то новая строка.
И нафига такая "помощь" пользователю?


А мне по барабану.
Я же сказал, что делаю так только если юзер сам три раза попросит меня об этом.
Кроме того, даже если я не попаду на старую запись, то "ничего не взорвется"


 
zorik ©   (2007-11-09 14:26) [29]

Ого! Какой интерес!

для Ega23 ©   (09.11.07 12:35) [6]
У меня так и есть. Я к похожему сам дошел. Есть форма редактирования в репозитории. Вызывается с параметром обозначающим добавление или редактирование, но вопрос именно в обновлении после изменений. Locate по ID работает идеально, но есть 3 но:
1. скорость
2. до вызова:
 line 3
> line 4 <курсор здесь
 line 5
 line 6
после вызава:
 line 1
 line 2
 line 3
> line 4 <курсор здесь
3. При удалениии курсор на первой позиции. Но с этим можно справится.

Использовать один TIBQuery для отображения и модификации даже с применением раздельных транзакций для чтения и записи ИМХО нехорошо не только из-за боязни там что-то потерять или не закрыть, а еще потому что запрос может быть сложным и состоять со сплошных join-ов.

Редактировать в гриде, тоже плохой вариант. Если есть всяческие комбобоксы, справочники и т.д. Да и как подтверждать запись. А так модальное окно -- и у пользователя нет вариантов -- или ok или cancel. Это не обсуждается


 
Reindeer Moss Eater ©   (2007-11-09 14:31) [30]

Маета это ненужная.
А печаль по поводу второго пункта вообще вне конкуренции.


 
Reindeer Moss Eater ©   (2007-11-09 14:33) [31]

Сделай позиционирвание опциональным.
Хочется юзеру изврата - пусть использует идеальный локейт, не хочет - не пользует.


 
Sergey13 ©   (2007-11-09 14:40) [32]

> [29] zorik ©   (09.11.07 14:26)
> Использовать один TIBQuery ...

Во первых не квери а датасет. Во вторых запрос на модификацию с джоинами это нонсенс в данном случае - редактируется одна таблица. В третьих переоткрывать на каждый чих сложной запрос состоящий из сплошных join-ов - уж куда как хорошо.

> и как подтверждать запись.

Как обычно commit-ом.


 
Ega23 ©   (2007-11-09 14:47) [33]


> 3. При удалениии курсор на первой позиции. Но с этим можно
> справится.


Ну запоминай перед удалением ID Next или Prior записи. Потом Locate на неё.


 
zorik ©   (2007-11-09 14:58) [34]

Sergey13 ©  (09.11.07 14:40) [32]
Сейчас попробую реализовать для одного датасета


 
Anatoly Podgoretsky ©   (2007-11-09 15:23) [35]

> Ega23  (09.11.2007 14:47:33)  [33]

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


 
Ega23 ©   (2007-11-09 15:43) [36]


> Только NEXT, обычно операции удаления делают сверху вниз


сначала не понял. Потом понял. Тогда так:
with dataSet do
if not isEmpty then
 if Eof then Prior else Next.



 
Anatoly Podgoretsky ©   (2007-11-09 16:12) [37]

> Ega23  (09.11.2007 15:43:36)  [36]

Подходит, только вторая строка лишняя, достаточно if Eof, но это не существенно.


 
Ega23 ©   (2007-11-09 16:13) [38]


> только вторая строка лишняя


Не, я к тому, чтобы ID не брать у записи, которой нет.


 
Anatoly Podgoretsky ©   (2007-11-09 17:03) [39]

> Ega23  (09.11.2007 16:13:38)  [38]

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


 
PEAKTOP ©   (2007-11-09 22:37) [40]

> zorik ©   (09.11.07 14:26) [29]

Я так понял, ты хочешь получить грид а-ля Excel, чтобы все "в живую" плюс изменения других пользователей ?
Возьми FIBPlus, почитай про транзакции у Димки Кузьменко (http://ibase.ru) и все у тебя получиться путем выставления свойств объектов :)

А InterBaseExpress - не более чем чудесная поделка от дяди Джеффа Овекэша :)



Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2008.04.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.021 c
2-1205145670
AeRo
2008-03-10 13:41
2008.04.06
Как с помощью Rectangle рисовать ПРОЗРАЧНЫЕ прямоугольники?


15-1203770359
Kerk
2008-02-23 15:39
2008.04.06
[MySQL] .. как открыть?


9-1168870634
Kav
2007-01-15 17:17
2008.04.06
Glscene скелетная анимация на шейдере


3-1194934491
Ega23
2007-11-13 09:14
2008.04.06
Getting Started


15-1203498690
Романыч
2008-02-20 12:11
2008.04.06
Флэшки не открываются





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский