Форум: "Базы";
Текущий архив: 2009.05.17;
Скачать: [xml.tar.bz2];
ВнизTClientDataSet + ADO + MSSQL Найти похожие ветки
← →
kaif © (2008-09-10 00:50) [0]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, но до этих событий, похоже, дело не доходит)
← →
kaif © (2008-09-10 01:15) [1]Похоже, моя задача проще решается без ClientDataSet.
Методом ADODataSet1.UpdateBatch().
Хотя соображения выслушать всегда полезно.
← →
Johnmen © (2008-09-10 09:06) [2]
> kaif ©
Тебе не нужет CDS, достаточно ADODataSet, как имеющего схожий функционал относительно локального кеширования.
← →
MsGuns © (2008-09-10 09:14) [3]Не представляя себе сути решаемой задачи, невозможно высказать какие-то соображения.
По поводу "умности" ADO. Есть куча статей в инете, где обсуждается именно эта особенность оболочки - "умение" разобраться в какой таблице что менять и глючность этого "умения".
Эта путаница не в последнюю очередь вынудила меня отказаться от прямого гридного редактирования датасета. Хотя, вполне допускаю, что при достаточнной настырности можно заставить АДО работать корректно во всех случаях, я же предпочитаю обходиться другими, более прозрачными технологиями.
ЗЫ. ИМХО, ветка оформлена не по правилам и может быть удалена,
← →
kaif © (2008-09-10 09:25) [4]Я выбросил CDS. Оставил только ADODataSet. Но так и не смог избавиться от редактирования сразу всех таблиц, которое он мне устроил. :(
Пришлось реализовывать обновление в обход, в прямом смысле слова.
Пожалуй ветку действительно можно удалить.
← →
Johnmen © (2008-09-10 09:29) [5]
> kaif © (10.09.08 09:25) [4]
Там где-то в параметрах можно указать, какая таблица должна апдейтиться.
Я не помню... sniknik подскажет.
← →
sniknik © (2008-09-10 10:37) [6]> Там где-то в параметрах можно указать, какая таблица должна апдейтиться.
Properties["Unique Table"].Value
и вообще
http://www.delphikingdom.com/asp/itemq.asp?Mode=1&ItemID=128
← →
kaif © (2008-09-10 11:00) [7]2 sniknik © (10.09.08 10:37) [6]
Спасибо. Properties["Unique Table"].Value сработал.
Но вот не могу задействовать
Update Criteria
Не знаю, что присвоить этому свойству. Мне нужно апдейтить только по первичному ключу. В статье говорится об adCriteriaKey, но такой константы в ADO нет.
← →
kaif © (2008-09-10 11:15) [8]Нет, показалось. К сожалению продолжает добавлять в таблицу справочника при инсерте. :(
Зато константу adCriteriaKey нашел.
← →
Правильный$Вася (2008-09-10 11:55) [9]
> Теперь я пытаюсь вызвать метод ClientDataSet1.ApplyUpdates(0);
в тяжелых случаях можно использовать Provider.BeforeUpdateRecord
← →
MsGuns © (2008-09-10 15:30) [10]Насколько я понял, ты не совсем по назначению используешь CDS
ИМХО, есть 2 основных его назначения:
1) "Отложенные" изменения
Датасет использует "прямое" подключение через провайдер, однако позволяет работать даже при потере соединения, сохраняя данные в кэше или даже на лок.диске. При возобновлении соединения делается попытка отправить изменения на сервер и перейти в "онлайн"
2) "Автономная" работа
Датасет динамически создается по "образу и подобию" исходного. Туда "ручками" заливаются данные из исходного, исходный закрывается (в т.ч. включая само соединение). Вся работа ведется в CDS с периодическими (по кнопке или соотв.событиям) сохранениями на лок.диске. По кнопке данные датасета последовательно одиночными параметрическими запросами update-delete-insert) переносятся на сервер. Все выполняется в единой транзакции, запускаемой "ручками" через соединение (ADOConnection.BeginTrans), разумеется с проверками результата записи. Если Ок, цикл продолжается и по его завершении транзакция подтверждается, датасет переоткрывается "напрямую" и работа возобновляется как бы с начала. Если возникла ошибка записи-удаления, транзакция откатывается, причина отображется на экране, ошибочная запись становится текущей в датасете.
Этот способ, возможно, выглядит не совсем "красиво", но работает превосходно именно в конкурентных ситуациях, когда несколько пользователей обращаются к одному и тому же сложному объекту, хранящемуся в БД, и объект должен "выделяться" лишь одному из них.
← →
MsGuns © (2008-09-10 15:35) [11]В "автономном" режиме запросто реализуется сеточная правка в эксельной манере - при этом не загружается сервер, нет лишних проверок на целостность, исключена вероятность взаимовлияния пользователей друг на друга при модификациях одних и тех же объектов БД и скорость работы не зависит ни от каких факторов, кроме, конечно, производительности ПК клиента.
← →
MsGuns © (2008-09-10 15:42) [12]Еще в пользу CDS:
Он абсолютно не зависит от источника в плане сортировок, фильтров и т.д. В нем есть даже агрегаты, позволяющие делать объединения и итоги "как в экселе" (ну или почти как). Кроме того, полностью управляем в плане что и когда отправлять на сервер. Каждая запись у него имеет статус, который можно анализировать ДО отправки данных провайдеру.
Единственный минус его (впрочем, вполне оборимый через добавление в uses Midas.pas или вроде того) - это неоходимость таскания Midas.dll, с которой могут быть проблемы (например, после установки на клиентский ПК какой-нибудь ранней версии Делфы)
← →
kaif © (2008-09-10 18:35) [13]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"", ""%вася%"""
Если бы мне кто-нибудь такое сказал, то я, пожалуй, действительно решил бы, что этот человек либо врет, либо у него с головой что-то не то.
← →
kaif © (2008-09-10 21:13) [14]У меня сейчас новая засада (уже 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 21:37) [15]Используй параметры, которые предварительно считывай из ХП (Parameters.Refresh)
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2009.05.17;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.005 c