![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TClientDataSet + ADO + MSSQL [D6, MSSQL]
kaif © (2008-09-10 00:50:00)2 MsGuns
г) в особо критичных ситуациях "гридного" редактирования не ленись использовать TClientDataSet со всеми его вкусностями (в т.ч. "тонкой" технологией управления кэшированием-отсылкой изменений) - ADO в сеточной режиме ведет себя иногда весьма капризно (особенно в конкурентных соединениях)
Я вот пытаюсь это сделать. С ClientDataSet раньше не работал.
Положил на одну форму:
ADODataSet1, DataSetProvider1 и ClientDataSet1.
Привязал их:
ClientDataSet1.ProviderName := DataSetProvider1;
DataSetProvider1.DataSet := ADODataSet1;
В ClientDataSet1 добавил persistent-поля в дизайнере с нужными именами и типами.
В ADODataSet1.CommandText вписал текст запроса детальной таблицы. Причем у меня там лежит JOIN двух таблиц (позиций заказов и справочника товаров)
Активизировал запрос.
Активизировал ClientDataSet1.
В верхней сетке (та, что связана с ADODataSet1) данные редактируются и тут же посылаются на сервер. Я вижу в Studio Express, как изменения проявляются в базе. Этот ADO+MSSQL провайдеры настолько умны, что он умудряются не только редактировать позиции заказа (количества), но и изменять наименование товара каким-то фантастическим образом в справочнике товаров.
То есть, похоже, на лету разбираются с тем, какие поля из каких таблицобъединения JOIN я изменяю. Хотя в общем-то мне все это нафиг не нужно. Я хочу (пока это желание присутствует) ручками управлять ситуацией так, чтобы самому в нужный момент сформировать все нужные запросы.
Пойдем далее.
Итак, вижу в нижней сетке , подключенной к ClientDataSet1, набор данных.
При редактировании в этой сетке вижу, что исходный набор в верхней сетке не изменяется, ничего на сервер не посылается. Я безумно рад этому обстоятельству. Значит, я на верном пути.
Теперь я пытаюсь вызвать метод
ClientDataSet1.ApplyUpdates(0);
У меня возникли некоторые трудности.
Возникает ошибка Invalid column name GOOD_NAME. Это как раз и есть поле справочника.
Все ли я в принципе делаю правильно?
Можно ли перехватить событие обновления датасета?
У меня не получилось (я пытался использовать OnWillChangeRecord и даже OnWillChangeField, но до этих событий, похоже, дело не доходит)
MsGuns (2008-09-10 21:37:00) [1]Используй параметры, которые предварительно считывай из ХП (Parameters.Refresh)
kaif (2008-09-10 21:13:00) [2]У меня сейчас новая засада (уже 5-я за трое суток).
Хранимая процедура принимает 3 параметра 2: типа datetime, один типа varchar(50). Процедура строит отчет. В Studio Express отчет прекрасно работает. В дизайн-тайме в ADO при указании параметров в объект-инспекторе тоже работает.
При попытке присвоить параметры рантайм, работает, но отчет выдает нулевые данные. Похоже, что параметры типа DateTime доходят криво.
Я пытался обойтись без параметров вообще.
Если явно присвоить строке CommandText в дизайнере:
SP_MYPROC '20080101', '20081010', '%вася%'
То потом рантайм методом Open отчет будет выведен правильно.
Если же рантайм присвоить ту же самую строку, отчет выводит нули.
CommandText := 'SP_MYPROC ''20080101'', ''20081010'', ''%вася%'''
Если бы мне кто-нибудь такое сказал, то я, пожалуй, действительно решил бы, что этот человек либо врет, либо у него с головой что-то не то.
Прошу прощения. Это сообщение ошибочно.
kaif (2008-09-10 18:35:00) [3]2 MsGuns ©
Сергей, спасибо за столь подробное разъяснение. Я обязательно тщательно изучу работу с CDS в любом случае, чтобы осознанно выбирать наилучший вариант в любой ситуации.
Так как работа у меня была тестовая и срочная, не столько на знание ADO, сколько нужно было быстро разобраться с MS SQL и обязательно при помощи стандартных компонентов Delphi6, то насколько это было возможно сделать в сжатые сроки, я пока остановился на решении:
ADODataSet.LockType := ltBatchOptimistic
ADODataSet.UpdateBatch() //по идее
Причем сумел задействовать только чтение и кеширование данных для свободного редактирования "количеств накладной" в сетке.
Обновления же я сделал пока совсем в лоб, обходом датасета в цикле и отправкой команд с помощью рантайм создаваемого TADOCommand. То есть в цикле создаю новые в во временной таблице, а затем одной командой удаляю все старые строки накладной, а новые - перекидываю в накладную при помощи insert into ... select from, а временную таблицу уничтожаю.
Это очень грубое решение, но времени совершенствовать не было, так как у меня было много более важных задач в самой базе данных (поддержка остатков при помощи триггеров, быстрый отчет о движении за период и т.д.).
Я долго бился (и сегодня вечером буду биться), пытаясь все же задействовать отправку методом ADODataSet.UpdateBatch().
Я надеюсь, что мне все же удастся заставить ADO отказаться пытаться вставлять в справочник значение-дубликатпри попытке вставить лишь новую строку в накладную.
Хотя меня этот момент уже бесит, если честно. Неужели разработчики самого ADO (или хотя бы дельфийской обертки) не могли сделать что-нибудь традиционное в виде 4 команд (SelectSQL, UpdateSQL, DeleteSQL, RefreshSQL), чтобы программист не мучился столько, пытаясь отговорить ADO делать то, что его вообще никто не просил...
Моя мечта - перейти на компоненты прямого доступа и забыть это все в кошмарном сне.
У меня сейчас новая засада (уже 5-я за трое суток).
Хранимая процедура принимает 3 параметра 2: типа datetime, один типа varchar(50). Процедура строит отчет. В Studio Express отчет прекрасно работает. В дизайн-тайме в ADO при указании параметров в объект-инспекторе тоже работает.
При попытке присвоить параметры рантайм, работает, но отчет выдает нулевые данные. Похоже, что параметры типа DateTime доходят криво.
Я пытался обойтись без параметров вообще.
Если явно присвоить строке CommandText в дизайнере:
SP_MYPROC '20080101', '20081010', '%вася%'
То потом рантайм методом Open отчет будет выведен правильно.
Если же рантайм присвоить ту же самую строку, отчет выводит нули.
CommandText := 'SP_MYPROC ''20080101'', ''20081010'', ''%вася%'''
Если бы мне кто-нибудь такое сказал, то я, пожалуй, действительно решил бы, что этот человек либо врет, либо у него с головой что-то не то.
MsGuns (2008-09-10 15:42:00) [4]Еще в пользу CDS:
Он абсолютно не зависит от источника в плане сортировок, фильтров и т.д. В нем есть даже агрегаты, позволяющие делать объединения и итоги "как в экселе" (ну или почти как). Кроме того, полностью управляем в плане что и когда отправлять на сервер. Каждая запись у него имеет статус, который можно анализировать ДО отправки данных провайдеру.
Единственный минус его (впрочем, вполне оборимый через добавление в uses Midas.pas или вроде того) - это неоходимость таскания Midas.dll, с которой могут быть проблемы (например, после установки на клиентский ПК какой-нибудь ранней версии Делфы)
MsGuns (2008-09-10 15:35:00) [5]В "автономном" режиме запросто реализуется сеточная правка в эксельной манере - при этом не загружается сервер, нет лишних проверок на целостность, исключена вероятность взаимовлияния пользователей друг на друга при модификациях одних и тех же объектов БД и скорость работы не зависит ни от каких факторов, кроме, конечно, производительности ПК клиента.
MsGuns (2008-09-10 15:30:00) [6]Насколько я понял, ты не совсем по назначению используешь CDS
ИМХО, есть 2 основных его назначения:
1) "Отложенные" изменения
Датасет использует "прямое" подключение через провайдер, однако позволяет работать даже при потере соединения, сохраняя данные в кэше или даже на лок.диске. При возобновлении соединения делается попытка отправить изменения на сервер и перейти в "онлайн"
2) "Автономная" работа
Датасет динамически создается по "образу и подобию" исходного. Туда "ручками" заливаются данные из исходного, исходный закрывается (в т.ч. включая само соединение). Вся работа ведется в CDS с периодическими (по кнопке или соотв.событиям) сохранениями на лок.диске. По кнопке данные датасета последовательно одиночными параметрическими запросами update-delete-insert) переносятся на сервер. Все выполняется в единой транзакции, запускаемой "ручками" через соединение (ADOConnection.BeginTrans), разумеется с проверками результата записи. Если Ок, цикл продолжается и по его завершении транзакция подтверждается, датасет переоткрывается "напрямую" и работа возобновляется как бы с начала. Если возникла ошибка записи-удаления, транзакция откатывается, причина отображется на экране, ошибочная запись становится текущей в датасете.
Этот способ, возможно, выглядит не совсем "красиво", но работает превосходно именно в конкурентных ситуациях, когда несколько пользователей обращаются к одному и тому же сложному объекту, хранящемуся в БД, и объект должен "выделяться" лишь одному из них.
Правильный$Вася (2008-09-10 11:55:00) [7]
> Теперь я пытаюсь вызвать метод ClientDataSet1.ApplyUpdates(0);
в тяжелых случаях можно использовать Provider.BeforeUpdateRecord
kaif (2008-09-10 11:15:00) [8]Нет, показалось. К сожалению продолжает добавлять в таблицу справочника при инсерте. :(
Зато константу adCriteriaKey нашел.
kaif (2008-09-10 11:00:00) [9]2 sniknik © (10.09.08 10:37) [6]
Спасибо. Properties['Unique Table'].Value сработал.
Но вот не могу задействовать
Update Criteria
Не знаю, что присвоить этому свойству. Мне нужно апдейтить только по первичному ключу. В статье говорится об adCriteriaKey, но такой константы в ADO нет.
sniknik (2008-09-10 10:37:00) [10]> Там где-то в параметрах можно указать, какая таблица должна апдейтиться.
Properties['Unique Table'].Value
и вообще
http://www.delphikingdom.com/asp/itemq.asp?Mode=1&ItemID=128
Johnmen (2008-09-10 09:29:00) [11]
> kaif © (10.09.08 09:25) [4]
Там где-то в параметрах можно указать, какая таблица должна апдейтиться.
Я не помню... sniknik подскажет.
kaif (2008-09-10 09:25:00) [12]Я выбросил CDS. Оставил только ADODataSet. Но так и не смог избавиться от редактирования сразу всех таблиц, которое он мне устроил. :(
Пришлось реализовывать обновление в обход, в прямом смысле слова.
Пожалуй ветку действительно можно удалить.
MsGuns (2008-09-10 09:14:00) [13]Не представляя себе сути решаемой задачи, невозможно высказать какие-то соображения.
По поводу "умности" ADO. Есть куча статей в инете, где обсуждается именно эта особенность оболочки - "умение" разобраться в какой таблице что менять и глючность этого "умения".
Эта путаница не в последнюю очередь вынудила меня отказаться от прямого гридного редактирования датасета. Хотя, вполне допускаю, что при достаточнной настырности можно заставить АДО работать корректно во всех случаях, я же предпочитаю обходиться другими, более прозрачными технологиями.
ЗЫ. ИМХО, ветка оформлена не по правилам и может быть удалена,
Johnmen (2008-09-10 09:06:00) [14]
> kaif ©
Тебе не нужет CDS, достаточно ADODataSet, как имеющего схожий функционал относительно локального кеширования.
kaif (2008-09-10 01:15:00) [15]Похоже, моя задача проще решается без ClientDataSet.
Методом ADODataSet1.UpdateBatch().
Хотя соображения выслушать всегда полезно.