Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Посчитать одинаковые записи, в гриде 
V
    Опции темы
Лена
Дата 16.4.2007, 18:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



При помощи этого кода я могу найти нужную запись:
Variant Rez = ADOQueryKey->Lookup("code", Form1->DBGrid1->Fields[0]->AsString, "code");
if(!Rez.IsNull())...
Если запись найдена, подскажите, как можно посчитать сколько раз она встречается в колонке грида?

PM MAIL   Вверх
Anikmar
Дата 16.4.2007, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 34
Всего: 59



Может быть быстрее отдельным запросом?
SELECT Count(Поле) AS Result FROM Table WHERE условие
PM MAIL ICQ   Вверх
Лена
Дата 16.4.2007, 19:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



Мне надо не много по другому. Пользователь вводит запись в колонку грида номер 1 и затем щелчком мыши переходит на другую строку в колонку например номер 3. Я хочу убедиться, что пользователь ввел запись, которой гарантировано, нет в колонке номер 1. Сейчас это реализовано так:
Код

ADOQueryKey->Open();

   Variant Rez = ADOQueryKey->Lookup("code", Form1->DBGrid1->Fields[0]->AsString, "code");
   if(!Rez.IsNull()&& Form1->DBGrid1->SelectedIndex == 0) /* */
             {
             sShowMessage("Такая запись уже есть. Введите другую");
             DataSet->Cancel();
             ADOQueryKey->Close();
             Abort();
             }

   ADOQueryKey->Close();

Этот код прекрасно работает, если пользователь сразу после ввода значения перейдет на другую строку в гриде. Если же пользователь продолжит редактировать эту же запись в соседней колонке, то при попытке post возникнет исключение, потому что в первой колонке записи должны быть разные. Для пояснения рисунок.



Присоединённый файл ( Кол-во скачиваний: 11 )
Присоединённый файл  new_1.jpg 31,22 Kb
PM MAIL   Вверх
Anikmar
Дата 16.4.2007, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 34
Всего: 59



Я для решения таких задач применял 2 метода:
1. Вводил ограничение Unique в саму БД и ловил исключение
2. (Более гуммано с точки зрения сбережения нервов пользователю) выводил редактирование строки в отдельную форму, где все проверки проводил при нажатии ок и по-русски объснял пользователю в каком месте он дурак  smile 
PM MAIL ICQ   Вверх
Лена
Дата 17.4.2007, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



В этом поле есть ограничение Unique. Подскажите, как правильно его обработать? Связь: ADOConnection1->ADOQuery->DataSetProvider->ClientDataSet->DataSource->Грид. В моем случае, который представлен на рисунке, происходит исключение. В каком событии правильно обработать эту ситуацию?
Думала просто простым циклом: если одинаковых записей больше двух, сделать отмену редактирования.



Это сообщение отредактировал(а) Лена - 17.4.2007, 11:01

Присоединённый файл ( Кол-во скачиваний: 9 )
Присоединённый файл  123.gif 14,62 Kb
PM MAIL   Вверх
Anikmar
Дата 17.4.2007, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 34
Всего: 59



Думаю самым простым в вашей ситуации будет обработчик BeforePost. В нем отдельным запросом проводить проверку и запрещать запись, если поля неподходят. Таким образом вы отсечете ситуацию ДО ее возникновения, а не после, как в случае с исключением.
PM MAIL ICQ   Вверх
Лена
Дата 17.4.2007, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



У меня как раз в обработчике ClientDataSetBeforePost, код который я приводила выше в своем втором сообщении. Как его правильно переделать?
PM MAIL   Вверх
Anikmar
Дата 17.4.2007, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 34
Всего: 59



Я с этим компонентом никогда не работал, но общая логика такая: Проверяете записываемые поля на допустимость их значений и в случае невозможности записи выдаете сообщение об ошибке и прерываете запись функцией Abort()

PM MAIL ICQ   Вверх
Vyacheslav
Дата 17.4.2007, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Цитата(Anikmar @  16.4.2007,  19:47 Найти цитируемый пост)
2. (Более гуммано с точки зрения сбережения нервов пользователю) выводил редактирование строки в отдельную форму, где все проверки проводил при нажатии ок и по-русски объснял пользователю в каком месте он дурак  

Отличный подход.
Вообще редактирование в непосредственно в гриде - это неправильно.



--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
Лена
Дата 17.4.2007, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



Цитата(Anikmar @  17.4.2007,  12:04 Найти цитируемый пост)
Проверяете записываемые поля на допустимость их значений 


Сообственно это и есть моя проблема. smile  Как это правильно делается? Наверняка существует стандартный код проверки ограничение Unique в  обработчике BeforePost. Я только смогла придумат код выше, но он не в полной мере подходит...

PM MAIL   Вверх
Vyacheslav
Дата 17.4.2007, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Цитата(Лена @  17.4.2007,  10:49 Найти цитируемый пост)
В этом поле есть ограничение Unique. Подскажите, как правильно его обработать? Связь: ADOConnection1->ADOQuery->DataSetProvider->ClientDataSet->DataSource->Грид. В моем случае, который представлен на рисунке, происходит исключение. В каком событии правильно обработать эту ситуацию?

Лена. Вся проблема у Вас возникла потому, что  Вы не контролируете  момент начала редактирования и его конца. Под контролем я понимаю наличие в коде команд Edit  и Post  при  устаноленном  AutoEdit в false. Наиболее правильным был бы подход, когда пользователю явно обозначен момент  начала редактирования и его конца. То есть, если он хочет отредактировать конкретную строку, он должен нажать кнопку Редактировать, получить  окно для редактирования, набрать все данные, визуально проверитиь их правильность и завершить редактирование, сохранив изменения или отказавшись от них. В этом случае у Вас есть всегда место, где перед сохранением, Вы можете проверить все данные на валидность
В Вашем случае скорее всего придется написать обработчик
Код

void __fastcall TForm1::ClientDataSet1PostError(TDataSet *DataSet,
      EDatabaseError *E, TDataAction &Action)
{

}


Добавлено @ 12:37
Цитата(Лена @  17.4.2007,  12:21 Найти цитируемый пост)
Как это правильно делается? Наверняка существует стандартный код проверки ограничение Unique в  обработчике BeforePost. Я только смогла придумат код выше, но он не в полной мере подходит...


Обычно никто не занимается проверкой того, что БД сделает за Вас. Она (БД)  должна сообщить (exception), а Вы выдать информацию в понятном вмде пользователю и предложить ему сценарий дальнейших действий


--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
Лена
Дата 17.4.2007, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



Цитата(Vyacheslav @  17.4.2007,  12:35 Найти цитируемый пост)
Вы не контролируете  момент начала редактирования и его конца. Под контролем я понимаю наличие в коде команд Edit  и Post  при этом  уставноленном  AutoEdit в false. Наиболее правильным был бы подход, когда пользователь явно обозначен момент  начала рекдактирования и его конца. То есть, если он хочет отредактировать конкретную строку, он должен нажать кнопку Редактировать, получить  окно для редактирования, набрать все данные, визуально проверитиь их пправильность и завершить редактирование, сохранив изменения или отказавшись от них. В этом случае у Вас есть всегда место, где перед сохранением, Вы можете проверить все данные на валидность


Да, теперь понимаю, что такой подход с окном для редактирования самый оптимальный. Я буду так реализовывать в следующих проектах. Просто этот проект надо уже отдать. Не готова вносить серьезные изменения. Скорость моего кодирования не впечатляет, могу не успеть. smile 
Вроде все работает. Вот только случайно наткнулась на ситуации описанную выше.
Для своего случая попробую, согласно вашего совета, ClientDataSet1PostError.



Это сообщение отредактировал(а) Лена - 17.4.2007, 12:46
PM MAIL   Вверх
Лена
Дата 17.4.2007, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



Всем хорош мой любимый Builder, только вот справочная система подкачала.
Жму F1 на PostError, вижу описание, а где же samples?!  smile 
Короче написала так:
Код

void __fastcall TDataModule2::ClientDataSet1PostError(TDataSet *DataSet,
      EDatabaseError *E, TDataAction &Action)
{
   if(E->Message == "Key violation.")
   {
   ShowMessage("Произошла ошибка. Записи в поле \"Ключ\" не должны повторяться");
   Action = daAbort;
   }
   else {
           ShowMessage("Произошла ошибка: " + E->Message);
           Action = daAbort;
          }
}

Но что-то не очень нравиться. Как бы добавить действие "Отменить редактирование", чтобы запись вернулась в исходное состояние? А то пользователь будет щелкать, не понимая в чем проблема, и будет получать ShowMessage. Хочется вернуть проблемную запись в первоначальный вид в этом обработчике. Это возможно?

P.S.
Наверное есть смысл снабдить все мои ClientDataSet-ы  обработчиком ClientDataSet1PostError?
И еще наверное хорошо бы добавить ClientDataSet1DeleteError?


Это сообщение отредактировал(а) Лена - 17.4.2007, 13:31
PM MAIL   Вверх
Vyacheslav
Дата 17.4.2007, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



А разве запись не возвращается в исходное состояние после daAbort
А так?
Код

void __fastcall TDataModule2::ClientDataSet1PostError(TDataSet *DataSet,
      EDatabaseError *E, TDataAction &Action)
{
   ShowMessage("Произошла ошибка " + E->Message);
   DataSet->Cancel();
   Action = daAbort;
}



Добавлено @ 13:49
Вообще, насколько я понимаю, у Вас постановка задачи не совсем верна. Откуда пользователю знать, есть или нет в БД такое число. Это же у Вас, как я понимаю, уникальный ключ. Ну так подставляйте его сами по результатам запроса от БД и запретите пользователю редактировать это поле.
Добавте обработчик OnNewRecord?в котором будете присваивать значение
Код

void __fastcall TForm1::ClientDataSet1NewRecord(TDataSet *DataSet)
{
Form1->DBGrid1->Fields[0]->AsInteger =  getNewValue();
}

где  getNewValue() - метод, который будет возвращать значение  запроса
SELECT MAX(Поле) + 1  AS Result FROM Table 





--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
Лена
Дата 17.4.2007, 13:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 879
Регистрация: 16.8.2006

Репутация: 11
Всего: 11



Цитата(Vyacheslav @  17.4.2007,  13:38 Найти цитируемый пост)
DataSet->Cancel();


М-да, слона не заметила! Это то что нужно, работает. Спасибо! Меня сбило столку слово daAbort, думала оно все вернет в исходный вид.


Если у меня в других гридах нет проблемы с дублированием, то достаточно ли будет для всех ClientDataSet-ов написать просто:
Код

void __fastcall TDataModule2::ClientDataSet1PostError( TDataSet *DataSet, EDatabaseError *E, TDataAction &Action)
{  
ShowMessage("Произошла ошибка: " + E->Message);  
Action = daAbort;
}
//--------------------------------------------------------------------------- 
void __fastcall TDataModule2::ClientDataSet1DeleteError(  TDataSet *DataSet, EDatabaseError *E, TDataAction &Action)
{  
ShowMessage("Произошла ошибка: " + E->Message); 
 Action = daAbort;
}

Или везде добавить DataSet->Cancel();? Или может еще что добавить в код?  smile 



P.S.
>Это же у Вас, как я понимаю, уникальный ключ.

Это поле в конечном итоге будут вводиться данные из другой программы, сделанной другим человеком. Пользователь не сможет ввести туда данные и эти данные будут уникальными. НО! Прежде чем это будет сделано, моя программа попадет к промежуточному звену людей, которые не знают, как все это будет выглядеть. Эти люди просто будут знакомиться с интерфейсом, и я не хочу их пугать не понятными исключениями, поэтому просто добавляю эту возможность перехвата.  smile 



Это сообщение отредактировал(а) Лена - 17.4.2007, 14:02
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0577 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.