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

Вниз

Insert, Update, Delete своими руками   Найти похожие ветки 

 
mvg_first   (2004-01-19 16:40) [0]

Добрый день мастера и остальные.
Заранее прошу прощения за возможно-банальный вопрос, но я настолько давно не общался с сообществом Delphi-программистов что правильно впорос поставить сейчас и не смогу. Поэтому прошу отнестись с пониманием и "больно не пинать"
Суть задачи.
Я пробую разрабатывать приложение для работы с БД MSSQL2000/ Для этого использую компоненты TADQQuery. В качестве контролов использую стандартный DBGrid.
Но сложность заключается в том что я хочу все запросы на вставку, добавление и удаление записей из отображаемых таблиц - делать самостоятельно. Т.е. когда пользователь добавляет в Гриде запись и пробует ее записать - что бы каким-то образом получить доступ к изменившимся полям выполнить операцию по вставке и если не случилось ошибки дать пользователю возможность работать с программой дальше, а в случае ошибки отменить вставку строки (вомзожно с выводом сообщения).
Компонет реализующий очень похожую функциональность в Делфи есть это TUpdateSQL - но он работает только с BDE версиями компонентов доступа к данным. Я же хочу использовать технологию ADO.
Пожалуйста порекомендуйте литературу (интеренет ресурсы), компоненты, образцы исходного кода - проработав которые я смогу самостоятельно разобраться и решить поставленную задачу.

Если к кому нибудь из Вас можно обратится посредством ICQ буду очень признателен (мой ICQ 84705448)


 
stone   (2004-01-19 16:43) [1]

Стучись. Моя аська в анкете.


 
Academic   (2004-01-19 16:48) [2]

Если хочешь все запросы на обновление делать самостоятельно,
то не используй на клиенте DBGrig, или создавай виртуальный DataSet, например TClientDataSet.


 
KSergey   (2004-01-19 16:53) [3]

> [1] stone © (19.01.04 16:43)
> Стучись. Моя аська в анкете.

Может выложите здесь?
А то не сподручно будет, если еще и я, а может и еще кто в аську попремся ;)


 
mvg_first   (2004-01-19 17:13) [4]

Пока нечего выкладывать поступило предложение обрабатывать событие BeforeInsert на ДатаСете который привязан к используюемому пользователем гриду.
Но я не уверен что это правильная идея.
Может быть что бы добавить ясности стоит описать порядок действий пользовтеля и тот порядок который я хотел бы выполнить (но незнаю как):
1. Программа выполняет запрос вида
SELECT * From TESTTABLE
и выводит результат запроса в грид. (тут никаких вопросов)
2. Далее пользователь нажинмает кнопку Инсерт, вводит данные в какие то поля и уходит с записи (т.е. должен по идее сработать метод пост)
3. В этом месте программа должна отловить попытку вставить запись, проанализировать какие поля пользователь изменил, выполнить Инсерт согласно установленных мной правил. При этом стандартный инсерт датасета выполнится недолжен
4. Программа возвращает в грид (или в датасет - тут мне непонятно) информацию которую нужно вернуть после выполнения инсерта.
Ну и т.д. и т.п.


 
Academic   (2004-01-19 17:21) [5]

На BeforePost(Delete), отлавливаешь изменения, вручную делаешь Update/Insert/Delete, Далле Abort.


 
mvg_first   (2004-01-19 17:30) [6]

А вызов Abort не отменит ли саму операцию инсерта как таковую? Почему то мне кажется как только я сделаю вызов Abort - на гриде добавляемая запись просто исчезнет потому как датасет ему скажет что операция отменена?


 
Academic   (2004-01-19 17:34) [7]


> mvg_first © (19.01.04 17:30)

Согласен, немного не подумал.
Но объясни, зачем это все делать вручную???


 
Academic   (2004-01-19 17:37) [8]


> А вызов Abort не отменит ли саму операцию инсерта как таковую?
> Почему то мне кажется как только я сделаю вызов Abort -
> на гриде добавляемая запись просто исчезнет потому как датасет
> ему скажет что операция отменена?


Блин, ну я торможу...
Тебе не все равно что она отменится?
Ты же делаешь Refresh?


 
Petr V. Abramov   (2004-01-19 17:49) [9]

В BeforePost выполняете Update/Insert-запросы ( в зависимости от Dataset.State), в BeforeDelete - Delete-запрос. Если Insert/Update-запрос возвращает какие-то параметры, их "еще не поздно" просто подставить в соотвествушие поля DataSet`а. Если возникает exception - у пользователя не получится уйти с записи, не исправив свои ошибки ввода или не отменив ввод.
Технология 100% рабочая, испробованная, но если ее использовать "в лоб", т.е. со стандартным Дельфовым набором компонентов, требует много ручного труда, причем именно ручного, а не умственного


 
mvg_first   (2004-01-19 18:01) [10]

А какие могут применяться нестандартные компоненты облегчающие задачу? Ибо мне предстоит работать с большим количеством разнообразных таблиц. И не хочется для каждой из них много механического труда применять если есть возможность это обойти


 
mvg_first   (2004-01-19 18:24) [11]

А на вопрос зачем мне это все - изначально я хотел работать на хранимых процедурах и селекты и инсерты и апдейты делать на них - но потом просто захотел решить этот вопрос для себя кардинально.
Т.е. я хочу сам управлять изменением записей на сервере. Тем более не всегда возможно отдать на откуп обновление данных датасету. Ведь могут быть сложные конструкции селектов с разветвленными Join-ами и сложными условиями.
Как тут быть? Как контроллировать логику добавления записей?


 
mvg_first   (2004-01-20 09:30) [12]

Больше предложений не поступит? Только через BeforePost?
Попоробовал BeforePost - но так и не понял как сформировав и выполнив свой запрос не дать выполнится инсерту по дефолту проходящему в Дата сете


 
Academic   (2004-01-20 10:00) [13]

Повторяю...
Даже если на BeforePost, после Abort, данные
в DBGrid пропадут, изменения уже прошли в базу.
Достаточно сделать Refresh данных, и они отобразятся.


 
DenK_vrtz   (2004-01-20 10:15) [14]

>Как тут быть? Как контроллировать логику добавления записей?

а все на сервере нельзя контролировать?
ключи, индексы, обработчики ошибок, триггера и т.д.


 
DDP1   (2004-01-20 10:51) [15]

Есть предложение. Вместо
SELECT * From TESTTABLE1 T1
JOIN TESTTABLE2 T2 ON T1.KOD=T2.KOD

пишем
SELECT * into #t From TESTTABLE1 T1
JOIN TESTTABLE2 T2 ON T1.KOD=T2.KOD
select * from #t

отлавливаем все измения во временной табличке, пишем свои изменения в реальные таблички.


 
Плохиш_   (2004-01-20 11:04) [16]

>mvg_first

1. grid.readonly := true
2. на форму кнопки insert, edit, delete
3. форму для ввода данньх
4. Думалка.Active := true


 
KSergey   (2004-01-20 11:14) [17]

> [14] DenK_vrtz © (20.01.04 10:15)
> >Как тут быть? Как контроллировать логику добавления записей?
>
> а все на сервере нельзя контролировать?
> ключи, индексы, обработчики ошибок, триггера и т.д.

Высказывание не по теме
Речь идет не о контроле целостности, а о контроле над отправляемыми запросами по модификации данных, которые (запросы) ADO тщательно пытается от нас сокрыть.

> [9] Petr V. Abramov © (19.01.04 17:49)
> В BeforePost выполняете Update/Insert-запросы ( в зависимости
> от Dataset.State), в BeforeDelete - Delete-запрос. Если
> Insert/Update-запрос возвращает какие-то параметры,

Не совсем понял о каких параметрах речь. Уточните, пожалуйста.
их "еще

> не поздно" просто подставить в соотвествушие поля DataSet`а.
> Если возникает exception - у пользователя не получится уйти
> с записи, не исправив свои ошибки ввода или не отменив ввод.
> Технология 100% рабочая, испробованная, но если ее использовать
> "в лоб", т.е. со стандартным Дельфовым набором компонентов,
> требует много ручного труда, причем именно ручного, а не
> умственного

Вслед за mvg_first хочется спросить: "как сформировав и выполнив свой запрос не дать выполнится инсерту по дефолту проходящему в Дата сете"??

[13] Academic © (20.01.04 10:00)
Повторяю...
Даже если на BeforePost, после Abort, данные
в DBGrid пропадут, изменения уже прошли в базу.
Достаточно сделать Refresh данных, и они отобразятся.

Refresh - это если запись у меня уже етьс (если о рефреше одной записи речь). А если она добавилась - как клиентская часть может этот рефреш сделать? Или имеется в виду переоткрыть запрос? На каждую запись? Не слишком ли накладно? Или я что-то недопонял?

Давно мне еще помнится как-то кто-то советовал такой метод: включить BatchUpdate, тогда ADO не посылает запросы, пока не вызвать какой-то там метод (не помню, ну да не важно). Предлагалось сыграть на этом (т.е. вызывать CancelBatch). Вот только на вопрос "дак а как данные-то в DataSet запихнуть, да чтобы еще на сервер новый назрос не ушел" - был дан атвет "а это ноу-хау"...
Так я и не знаю до сих пор как это сделать.


 
DenK_vrtz   (2004-01-20 11:52) [18]

>KSergey ©

>Высказывание не по теме
>Речь идет не о контроле целостности, а о контроле над
>отправляемыми запросами по модификации данных, которые
>(запросы) ADO тщательно пытается от нас сокрыть.

не согласен!
Смотрим [11].
Логику ввода данных реально проверять на сервере, а не заниматься эти на клиете. Я не прав?

Сергей, или я сути вопроса не понимаю?


 
KSergey   (2004-01-20 12:40) [19]

> [16] Плохиш_ (20.01.04 11:04)
> 1. grid.readonly := true

А если надо именно как раз grid.readonly := false?

> 4. Думалка.Active := true

Этой темой интересуюсь давно, однако постоянно вижу одно и тоже: рассказывают очевидные в принципе вещи про то, что сесть надо на BeforeUpdate/Insert и отсылать свой запрос.
Но как только касается как раз самого узкого места "как же заставить не отправляться запрос движком ADO, однако обновить DataSet" - тут же либо молчок, либо что-то невразумительное, либо думай сам, "ноу-хау". Так остальное - оно и так очевидно!!! Дак уж разжуйте хоть раз до конца, хоть кто-нибудь, "ну что вам, трудно чтоли?"!

Вот и Petr V. Abramov утверждает, что у него "Технология 100% рабочая", однако тоже недосказывает... Хотя пока надежды не теряю услышать его комментарии.

> [18] DenK_vrtz © (20.01.04 11:52)
> Сергей, или я сути вопроса не понимаю?

Этого я не знаю ;)
Впрочем, как писал уже не один раз - самое узкое место для меня и до сих пор не понятое - "как заставить не отправляться запрос движком ADO, однако обновить DataSet". А то, что логику можно проверить на сервере - это не суть важно, на мой взляд. Т.е. и так понятно, что раз я сам формирую запрос на изменение данных - то это может быть что угодно. И под словом "контролировать" понимается, как я думаю, не контроль за целостностью данных, а контроль за отправляемыми запросами на сервер.

Я пока вижу лишь один способ обновлять DataSet: рефреш записи, однако если для модифицируемой записи это еще выполнимо, то для вновь вставленной - переоткрывать весь DataSet? Как-то не очень это здорово, по-моему... А как иначе - не знаю я...

> [15] DDP1 (20.01.04 10:51)
> пишем
> SELECT * into #t From TESTTABLE1 T1
> JOIN TESTTABLE2 T2 ON T1.KOD=T2.KOD
> select * from #t

Да, предложение так же не ново. Можно, факт. Можно даже создавая временнубю таблицу сразу создавать и тригера, которые будут прямо на сервере править реальные таблички, вот только как-то через чур заумно получается, на мой взгляд. Хотя многие проблемы действительно можно решить. С другой стороны - тогда уж проще вообще табличку в памяти организовать - получится точно менее ресурсоемко при той же функциональности.
Причем, что досадно, ну была же у борланда шикарная технология с UpdateSQL! Ну ведь действительно прекрасно придумано. А в ADO - ну нету такого и все... Хотя я и понимаю, что UpdateSQL - чисто борландовская примочка. К слову сказать, в библиотеке VGLibrary есть ADO-компоненты и именно с UpdateSQL. Но давно она что-то не развивается уже.


 
DDP1   (2004-01-20 13:27) [20]

KSergey © (20.01.04 12:40) [19]
А вто статья есть
http://www.delphikingdom.com/treasury/adocomp.htm
Я правда не разбирался


 
KSergey   (2004-01-20 15:12) [21]

> [20] DDP1 (20.01.04 13:27)

А это да, это есть такое.
Правда, в подобных случаях меня всегда смущает фраза "Это может способствовать быстрому переводу программ с BDE на ADO". Как я понимаю, автор хочет сказать, что это решение "для ленивых", вроде как и без этого можно обойтись...
Ну либо я напрасно так это все понимаю.


 
mvg_first   (2004-01-20 16:13) [22]

Плохиш_
Такой банальный вариант - давно эксплуатируется - меня не устравивает - мне нужно пользователю предоставить изменение менно в гриде данных - ибо данные однотипного образца и скорость ввода данных в гриде будет выше.
DenK_vrtz
Мне не нужно контроллировать логику работы БД (вернее конкретно в этом вопросе) мне нужно самостоятельно составить запрос и не дать этот запрос сделать ADO-шному датасету.
И поэтому никаких временных таблиц дополнительных транзакций и прочего не нужно. В бд уже есть своя логика завязанная на многих факторах и только из-за того что клиентское приложение не может правильный запрос послать - я ее переделывать не собираюсь.
KSergey
Присоединяюсь к Вам в поисках решения по этому вопросу. Если вдруг поиски увенчаются успехом и результат не будет ноухау - не соблаговолите ли Вы известить о результатах меня?

To ALL
Вопрос не закрываю и буду рад дальнейшим предложениям и советам.


 
Arm79   (2004-01-20 16:51) [23]

Собственно говоря, я немного не понял. Зачем столько мути? Вместо UpgateSQL предлагаю использовать ADOCommand в режиме Command
Text.


 
mvg_first   (2004-01-20 17:42) [24]

Arm79
Краткий алгоритм в студию!!!
Основная проблема при выполнении изменений в гриде - недать датасету выполнить внутренний запрос к БД - как это решается с помощью ADOCommand?


 
KSergey   (2004-01-21 08:48) [25]

Off
Вот, я же говорил: идет множество очевидных предложений не по сути, как только в лоб спрашиваешь "так как же в конце концов" (см., например, ответ mvg_first для Arm79) - так все...

To > [9] Petr V. Abramov © (19.01.04 17:49)
> Технология 100% рабочая, испробованная, но если ее использовать
> "в лоб", т.е. со стандартным Дельфовым набором компонентов,
> требует много ручного труда, причем именно ручного, а не
> умственного

Может вы все же сможете поделиться 100% рабочей технологией с общественностью? Любой. Хоть в лоб. хоть по лбу - уже не важно ;)
(не хотелось бы думать, что уверения про 100% были просто для красного словца...)

> [22] mvg_first © (20.01.04 16:13)
> KSergey
> не соблаговолите ли Вы известить о результатах меня?

Забуду, стопудово.
Максимум что могу обещать - опубликовать на этом форуме.


 
mvg_first   (2004-01-21 11:06) [26]

В процессе длительних ковыряний (вчера до часу ночи сидел) пришел к выводу что один из "человеческих" вариантов - это написать свой потомок TADOCustomDataSet и переопределить в нем метод InternalPost. Вызывая Refresh - у объекта RecordSet (тот который чиста адошный)


 
mvg_first   (2004-01-27 13:31) [27]

Тут порекомендовали использовать View на сложные таблици и INSTEAD OF тригерры - но попробовал и получается чепуха какая то. Если я из Query Analizer выполняю инсерт то триггер отрабатыавет как и задумаывалось. А если я загоняю селект из этой вьюхи в обыкновенную ADOQuery то при добавлении записи выполняется инсернт непосредственно в таблицу на которую смотрит View??? Никто с таким не сталкивался?


 
sniknik   (2004-01-27 13:39) [28]

> Основная проблема при выполнении изменений в гриде - недать датасету выполнить внутренний запрос к БД
и это проблема?
ADODataSet.Connection:= nil;
все ни один не прорвется. ;о) а дальше все через ADOCommand руками.


 
mvg_first   (2004-01-27 15:19) [29]

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

Я пробовал вариант - переопределить метод InternalPost у TCustomADODataset - но не могу разобраться с позиционированием записи если сделать IтternalRequery - запись прыгает всегда на первую строчку. Независимо от того куда добавляли запись.


 
sniknik   (2004-01-27 15:57) [30]

> Дык а как потом обновить данные в гриде (даже если и принять Ваш метод)
заявление к чему относится? к ADODataSet.Connection:= nil;?
ну вы же хотели руками, вот и в датасете тоже руками для грида изменения делай.
непойму я вас, то нужно все руками то когда этого добились это же и не нравится.

> ... мало того добавить запись нужно еще что бы пользователь увидел
> ее и после добавления как раз оказался спозиционированным на ней.
ага, понял. допустим я пользователь, задумчиво редактирую строку в гриде не не переходя между записями чтобы случайно post не сделался, т.к. не уверен в том что мне окончательно нужно (может esc нажать для сброса и возврата исходного), и вдруг бабах новая запись и я на ней, и то что я не дописал благополучно записалось на середине неоконченое (конец сомнениям), и старую я не помню и даже где она находится не смотрел. ??? хорошая система. возьму на вооружение (напишу брошурку как делать не надо).
оно конечно хозяин барин, и возможно в конкретном случае именно это и нужно, но всеже.


 
SergSuper   (2004-01-27 16:24) [31]


> А если я загоняю селект из этой вьюхи в обыкновенную 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.


 
denisov   (2004-01-27 17:11) [32]


> mvg_first © (19.01.04 18:01) [10]


Не читая дальше, скажу, что в аналогичной ситуации использую TVirtualStringTree - очень мощная вещь, "этакая помесь грида и тривью", в добавок хорошая ХР 3D-графика..). Один раз сделал запрос, поместил данные в поля структуры ( type record .. end), на которую есть указатель в созданной строке(ветке - VirtualNode), и в путь. На операции изменения-инсерта в компоненте обрабатываешь все ручками, полный контроль. При необходимости обновления вырираещь селектом одну строку данных, делаешь изменения в данных компонента - дешево и сердито. Для несложного запроса ещё и быстро. Есть ещё плюсы, сам найдешь.


 
Polevi   (2004-01-27 17:28) [33]

используй TClientDataset-TDatasetProvider-TADODataset
провайдер позволяет реализовать механизм, подобный TUpdateSQL
а представление данных в XML позволяет сделать все что угодно с помощью парсинга и модификации этого самого XML перед заливкой его в TClientDataset или перед передачей провайдеру


 
mvg_first   (2004-01-27 17:53) [34]

2>denisov
А как насчет тормозов на количестве записей > 5000? (только не надого говорить что у меня неправильная логика клиента - я про это и сам много знаю - но я пишу систему обработки прайсов и клиент хочет видеть все товары в одном списки и помечая их группами изменять цены)


 
mvg_first   (2004-01-27 17:58) [35]

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


 
sniknik   (2004-01-27 18:15) [36]

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 18:16) [37]

denisov
Ссылочку плиз дай? Не нашел :(


 
denisov   (2004-01-27 18:22) [38]


> mvg_first © (27.01.04 17:53) [34]

Разбей их на группы сам..)
А какая проблема в том что записей 5000?


 
jocko   (2004-01-28 00:11) [39]

Сколько всего понаписано, а зачем так сложно?
Человек хочет сделать все правильно, а вы ему советуете сделать как всегда...
Посмотри ltBatchOptimistic - помоему решает все вопросы.
Добавь в модуль данных ActionList в нем действия, например Save, Insert и Delete (только не стандартные, а простые) в Execute напиши вызовы нужных хранимых процедур через ADOCommand, а в качестве параметров передай нужные поля ADODataset и ВСЕ!!!
И не слушай про тригеры, вьюхи и тд.
Из литературы BOL и Delphi Help.


 
mvg_first   (2004-01-28 09:01) [40]

denisov
Так таки и не подскажешь где поискать этот твой VirtualStringTree?



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

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

Наверх





Память: 0.59 MB
Время: 0.035 c
14-80101
MakNik
2004-02-03 12:03
2004.02.25
книга по Delphi


3-79589
ulyanitsky
2004-01-25 22:09
2004.02.25
Создание структуры БД. Что лучше?


11-79690
ratamahatta
2003-06-05 18:44
2004.02.25
Размер заголовков в TKOLTabControl


3-79574
Бывающий
2004-01-29 12:15
2004.02.25
Kак открыть файл XLS RaedOnly? помогите ПЛЗ!


14-80164
ИМХО
2004-02-01 03:40
2004.02.25
Американские баксы, дядя Сэм и пр.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский