![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Insert, Update, Delete своими руками [D7, MSSQL]
mvg_first © (2004-01-19 16:40:00)
Добрый день мастера и остальные.
Заранее прошу прощения за возможно-банальный вопрос, но я настолько давно не общался с сообществом Delphi-программистов что правильно впорос поставить сейчас и не смогу. Поэтому прошу отнестись с пониманием и "больно не пинать"
Суть задачи.
Я пробую разрабатывать приложение для работы с БД MSSQL2000/ Для этого использую компоненты TADQQuery. В качестве контролов использую стандартный DBGrid.
Но сложность заключается в том что я хочу все запросы на вставку, добавление и удаление записей из отображаемых таблиц - делать самостоятельно. Т.е. когда пользователь добавляет в Гриде запись и пробует ее записать - что бы каким-то образом получить доступ к изменившимся полям выполнить операцию по вставке и если не случилось ошибки дать пользователю возможность работать с программой дальше, а в случае ошибки отменить вставку строки (вомзожно с выводом сообщения).
Компонет реализующий очень похожую функциональность в Делфи есть это TUpdateSQL - но он работает только с BDE версиями компонентов доступа к данным. Я же хочу использовать технологию ADO.
Пожалуйста порекомендуйте литературу (интеренет ресурсы), компоненты, образцы исходного кода - проработав которые я смогу самостоятельно разобраться и решить поставленную задачу.
Если к кому нибудь из Вас можно обратится посредством ICQ буду очень признателен (мой ICQ 84705448)
mvg_first (2004-01-29 09:50:00) [21]
Насчет использования VIEW c INSTEAD OF триггерами.
Вчера же опять попробовал создать вьюшку но уже с опцией WITH VIEW_METADATA, теперь действительно начали срабатывать триггеры на добавление. Но тут же наткнулся на одну интересную вещь. Использовал стандартные компоненты. В тригере вместо вставки добавляемых значений сделал вставку простой текствой строки в текстовое поле (строка точно не соответствовала добавляемым из грида значениям)
ПОсле этого при попытка добавить в гриде запись добавление происходило но в гриде оставались значения занесенные туда пользователем, а те данные которые реально попадают в таблицу с использованием INSTEAD OF триггера - неотображались - пока не переоткроешь таблицу :( Именно этот факт и вызывает неудовольствие с моей стороны.
mvg_first (2004-01-29 09:43:00) [22]
/denisov (28.01.04 19:43) [43]/
Ну а насчет VirtualStringTree - то я к этому времени уже сам нашел, вчера дома поковырял (мощнейшая штука ничего не скажешь) особенно если вкурить во все ее тонкости. Но непонравилось две вещи. Когда к ней подключаются эдиты - они выглядят наложенными сверху а не встроенными в компонент :( Даже не попадают в рамки редактируемого нода. (я это вкорне не приветствую) И второе так и не разобрался как же сделать там возможность начинать редактирование без клика мышью по ноду или без нажатия кнопки F2/ Так как это делается в ДБГриде. Нажимаешь Энтер и начинаешь редактировать еще раз Энтер - заканчиваешь редактировать поле???
mvg_first (2004-01-29 09:38:00) [23]
В догонку (предыдущий пост написал вчера но почему то сайт лежал что ли вообще отправить немог) дома попробовал больше поиграться с вышеописанным алгоритмом. Понял почему не обновляется поле ID - оно автоинкрементное и по определению обновлятся не может. Но все равно проблемы это не решает. Если у меня после инсерта сделанного самостоятельно - кроме измененных пользователем полей меняются еще и другие поля (например заполняется поле PostDateTime в триггере) - то при таком подходе они не обновляются в гриде (вернее мне придется заново, получать это все из грида и полностью переприсваивать все поля отображаемые в гриде руками - объясните мне полезность такого метода?
mvg_first (2004-01-29 09:17:00) [24]
sniknik
Попробовал. Да действительно если отключать Connection := nil то данные не отсылаются, но я против этого и не спорил. Но по пунктам:
В AfterPost вставка записи не канает :) Потому как в этот момент запись в гирде уже фактически запостилась.
Поэтому написал в методе BeforePost. Следующий код
if ADOQuery1.State = dsInsert then
begin
ADOCommand1.CommandText := "INSERT TABLE1 (TestStr) VALUES(:TestStr) SELECT :ID = SCOPE_IDENTITY()";
ADOCommand1.Parameters.ParamByName("TestStr").Value := DataSet.FieldByName("TestStr").Value;
ADOCommand1.Parameters.ParamByName("id").Direction := pdOutput;
ADOCommand1.Parameters.ParamByName("Id").DataType := ftInteger;
ADOCommand1.Execute;
ADOQuery1.FieldByName("Id").ReadOnly :=false;
ADOQuery1.FieldByName("Id").Value := ADOCommand1.Parameters.ParamByName("Id").Value;
end;
При этом записи добавляются конечно, но в гриде поле ID не обновляется.
Так что даже в этом случае - слегка...
И тут же следующий вопрос а если у меня при добавлении 1-го поля в таблицу происходит заполнение других полей (например триггер срабатывает) как мне эти поля тоже в ручную обрабатывать? А не слишком ли это накладно - эфеект использования DBGrida как таковго теряет смысл :(
denisov (2004-01-28 19:43:00) [25]
> mvg_first © (28.01.04 09:01) [40]
В интернете, разумеется.) www.lischke-online.de де то там
http
> sniknik © (28.01.04 11:27) [42]
Левый он чуть более борландовских, к тому же документация в наличии, до безобразия в наличии
sniknik (2004-01-28 11:27:00) [26]
mvg_first © (28.01.04 11:09) [41]
странный человек, ты скажи ты пробуеш чегонибудь ([36] к примеру), или продолжаеш теоретизировать?
чего до сих пор непонятно? единственное чего не обсуждали пока в этом варианте
> а датасет должен вызвать при этом мой запрос.
чем AfterPost не подходит? (в отсоедененном как раз сработает
> не дать выполнится запрос встроенному в Адошный рекодсет)
или, придумай другую причину по которой этот вариант не проходит. (пока все выдвигаемые "требования" один в один сходятся с действительностью)
> Так таки и не подскажешь где поискать этот твой VirtualStringTree?
почему думаеш что поможет левый компонент без документации если не можеш разабратся в стандартном с кучей хелпов и описаний?
mvg_first (2004-01-28 11:09:00) [27]
jocko
Я хочу без Экшин-листов :) Хочу просто в гриде добавить запись а датасет должен вызвать при этом мой запрос. И не дать выполнится запрос встроенному в Адошный рекодсет. И после выполнения запроса обновить грид и стать на ту же запись которую добавил или на которую должен встать в результате перемещения после добавления.
Если использовать БатчОптимистик - то как сказать что бы он все таки не делал запрос?
mvg_first (2004-01-28 09:01:00) [28]
denisov
Так таки и не подскажешь где поискать этот твой VirtualStringTree?
jocko (2004-01-28 00:11:00) [29]
Сколько всего понаписано, а зачем так сложно?
Человек хочет сделать все правильно, а вы ему советуете сделать как всегда...
Посмотри ltBatchOptimistic - помоему решает все вопросы.
Добавь в модуль данных ActionList в нем действия, например Save, Insert и Delete (только не стандартные, а простые) в Execute напиши вызовы нужных хранимых процедур через ADOCommand, а в качестве параметров передай нужные поля ADODataset и ВСЕ!!!
И не слушай про тригеры, вьюхи и тд.
Из литературы BOL и Delphi Help.
denisov (2004-01-27 18:22:00) [30]
> mvg_first © (27.01.04 17:53) [34]
Разбей их на группы сам..)
А какая проблема в том что записей 5000?
mvg_first (2004-01-27 18:16:00) [31]
denisov
Ссылочку плиз дай? Не нашел :(
sniknik (2004-01-27 18:15:00) [32]
mvg_first © (27.01.04 17:58) [35]
какие обиды?
так понимаю возможностей ADO и в частности TADODataset ты не знаеш, по пунктам.
TADODataset.Open; //получили рекордсет (важно, должен локальный курсор стоять)
ADODataSet.Connection:= nil; //отключили от конекта (данные остались!)
ADODataSet.Sort:= "ID"; //считаем что ID это ключь (первичный индекс)
все, изменяй ID в гриде посмотри что будет, все изменения на сервер посылать нужно руками (не этого добивались?).
кстати если ID действительно ключь (а не просто считаем так), еще операция
ADODataSet.FieldByName("ID").ReadOnly:= false;
а то редактировать не даст.
mvg_first (2004-01-27 17:58:00) [33]
sniknik
Ты сам понял что сказал???? (не вобиду) я не понял. В полне резонная ситуация когда я добавляю запись, вношу изменения во все поля и перехожу на следующую строку - то очень бы хотелось видеть куда эта запись "упала". Т.к. это и делается в стандартном датасете (если например есть индекс первичный) при добавлении записи - строка перемещается и вместе со строкой и фокус пользователя.
А то как ведут себя пользователи - это вобще отдельный разговор иногда они вытворяет такое что и в кошмарном сне не приснится :) И недай бог твоя программа не снабжена защитами от дурака - все пипец :) Ты же еще и виновать
mvg_first (2004-01-27 17:53:00) [34]
2>denisov
А как насчет тормозов на количестве записей > 5000? (только не надого говорить что у меня неправильная логика клиента - я про это и сам много знаю - но я пишу систему обработки прайсов и клиент хочет видеть все товары в одном списки и помечая их группами изменять цены)
Polevi (2004-01-27 17:28:00) [35]
используй TClientDataset-TDatasetProvider-TADODataset
провайдер позволяет реализовать механизм, подобный TUpdateSQL
а представление данных в XML позволяет сделать все что угодно с помощью парсинга и модификации этого самого XML перед заливкой его в TClientDataset или перед передачей провайдеру
denisov (2004-01-27 17:11:00) [36]
> mvg_first © (19.01.04 18:01) [10]
Не читая дальше, скажу, что в аналогичной ситуации использую TVirtualStringTree - очень мощная вещь, "этакая помесь грида и тривью", в добавок хорошая ХР 3D-графика..). Один раз сделал запрос, поместил данные в поля структуры ( type record .. end), на которую есть указатель в созданной строке(ветке - VirtualNode), и в путь. На операции изменения-инсерта в компоненте обрабатываешь все ручками, полный контроль. При необходимости обновления вырираещь селектом одну строку данных, делаешь изменения в данных компонента - дешево и сердито. Для несложного запроса ещё и быстро. Есть ещё плюсы, сам найдешь.
SergSuper (2004-01-27 16:24:00) [37]
> А если я загоняю селект из этой вьюхи в обыкновенную ADOQuery
> то при добавлении записи выполняется инсернт непосредственно
> в таблицу на которую смотрит View??? Никто с таким не сталкивался?
Надо делать вью с опцией WITH VIEW_METADATA
VIEW_METADATA
Specifies that SQL Server will return to the DBLIB, ODBC, and OLE DB APIs the metadata information about the view, instead of the base table or tables, when browse-mode metadata is being requested for a query that references the view. Browse-mode metadata is additional metadata returned by SQL Server to the client-side DB-LIB, ODBC, and OLE DB APIs, which allow the client-side APIs to implement updatable client-side cursors. Browse-mode meta data includes information about the base table that the columns in the result set belong to.
For views created with VIEW_METADATA option, the browse-mode meta data returns the view name as opposed to the base table names when describing columns from the view in the result set.
When a view is created WITH VIEW_METADATA, all its columns (except for timestamp) are updatable if the view has INSERT or UPDATE INSTEAD OF triggers. See Updatable Views later in this topic.
sniknik (2004-01-27 15:57:00) [38]
> Дык а как потом обновить данные в гриде (даже если и принять Ваш метод)
заявление к чему относится? к ADODataSet.Connection:= nil;?
ну вы же хотели руками, вот и в датасете тоже руками для грида изменения делай.
непойму я вас, то нужно все руками то когда этого добились это же и не нравится.
> ... мало того добавить запись нужно еще что бы пользователь увидел
> ее и после добавления как раз оказался спозиционированным на ней.
ага, понял. допустим я пользователь, задумчиво редактирую строку в гриде не не переходя между записями чтобы случайно post не сделался, т.к. не уверен в том что мне окончательно нужно (может esc нажать для сброса и возврата исходного), и вдруг бабах новая запись и я на ней, и то что я не дописал благополучно записалось на середине неоконченое (конец сомнениям), и старую я не помню и даже где она находится не смотрел. ??? хорошая система. возьму на вооружение (напишу брошурку как делать не надо).
оно конечно хозяин барин, и возможно в конкретном случае именно это и нужно, но всеже.
mvg_first (2004-01-27 15:19:00) [39]
Дык а как потом обновить данные в гриде (даже если и принять Ваш метод) мало того добавить запись нужно еще что бы пользователь увидел ее и после добавления как раз оказался спозиционированным на ней.
Я пробовал вариант - переопределить метод InternalPost у TCustomADODataset - но не могу разобраться с позиционированием записи если сделать IтternalRequery - запись прыгает всегда на первую строчку. Независимо от того куда добавляли запись.
sniknik (2004-01-27 13:39:00) [40]
> Основная проблема при выполнении изменений в гриде - недать датасету выполнить внутренний запрос к БД
и это проблема?
ADODataSet.Connection:= nil;
все ни один не прорвется. ;о) а дальше все через ADOCommand руками.