Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Добавление ADO-параметров в ран-тайм [D7, MSSQL]


Страницы:   1 2

Ega23 ©   (2008-10-03 14:42:00) 

Похоже уже глаз замылился.

Есть MSSQL, работаю через ODBC (так надо).
Есть таблица create table testtbl (uid int)
Есть некий класс TDBConnector с методом


function TDBConnector.DBExecCommand(ac: TADOCommand): Boolean;
begin
 Result := False;
 if FState<>csConnected then Exit;
 try
   ac.Connection := FConnection;
   try
     ac.Execute;
     Result := True;
   except on E : Exception do
     OnException('TDBConnector.DBExecCommand : ' + E.message);
   end;
 finally
   ac.Connection := nil;
 end;
end;


т.е. приняли на вход ADOCommand, проверили состояние коннекта, исполнили команду, отцепили от неё коннекшн.

Бросаю на форму TADOCommand.
выставляю в дизайн-тайм ParamCheck=False; CommandText = insert into testtbl (uid) values (:uid)
Ручками в дизайн-тайм добавляю параметр uid, выставляю Direction, DataType и Size.

В ран-тайм выполняю код:

procedure TForm2.Button4Click(Sender: TObject);
var
 paran : TParameter;
begin
 param := ADOCommand1.Parameters.FindParam('uid');
 if param=nil then
 begin
   param := ADOCommand1.Parameters.AddParameter;
   param.Name := 'uid';
   param.DataType := ftInteger;
   param.Direction := pdInput;
   param.Size := 4;
 end;

 ADOCommand1.Parameters.ParamByName('uid').Value := 10;
 if FConn.DBExecCommand(ADOCommand1) then
     ShowMessage('OK')
   else
     ShowMessage('Fail');
end;


всё ОК.

Добавляю в начало метода строчку
ADOCommand1.Parameters.Clear;
Всё ОК.

А вот теперь беру и делаю так:
В дизайн-тайм кладу чистый TADOCommand, не выставляю ему никаких свойств.

Код метода:


procedure TForm2.Button4Click(Sender: TObject);
var
 paran : TParameter;
begin

 ADOCommand1.ParamCheck := False;
 ADOCommand1.CommandText := 'insert into testtbl (uid) values (:uid)';
 ADOCommand1.Parameters.Clear;
 param := ADOCommand1.Parameters.FindParam('uid');
 if param=nil then
 begin
   param := ADOCommand1.Parameters.AddParameter;
   param.Name := 'uid';
   param.DataType := ftInteger;
   param.Direction := pdInput;
   param.Size := 4;
 end;

 ADOCommand1.Parameters.ParamByName('uid').Value := 10;
 if FConn.DBExecCommand(ADOCommand1) then
     ShowMessage('OK')
   else
     ShowMessage('Fail');

end;


Выполняю, на Execute вижу ошибку Incorrect syntax near ':'
В профайлере на сервер запрос долетает в виде 'insert into testtbl (uid) values (:uid)'

Что не так делаю?


Вариант   (2008-10-06 12:49:00) [1]


>  Вариант   (06.10.08 12:09) [35]

Дополню - http://devart.com/sdac/.есть и для других СУБД


ANB   (2008-10-06 12:32:00) [2]


> kaif ©   (05.10.08 02:25) [27]

Я как то уже поднимал вопрос в форуме о некой урезанности функционала ADO по сравнению с тем же QA.
Получил ответ, что я не умею его готовить :)
Несмотря на применение всех советов, которые мне тут надавали, решить мою задачу удалось только прямым вызовом DBLib. И действительно, в ADO.Net таких проблем нету.

Короче, решений 3 :
1. Пользвать ADO с учетом граблей
2. Написать свои компоненты с использованием DBLib (я бы сказал - не простой способ)
3. Способ который выбрал я - перейти на оракл, для него есть весьма толковые нативные компоненты.


Вариант   (2008-10-06 12:09:00) [3]


> kaif ©   (06.10.08 01:36) [29]


> Какие конкретно (платные и бесплатные) существуют и какие
> из них кажутся Вам наиболее удачными?


MSDAC


Ega23   (2008-10-06 12:04:00) [4]

Да, с ? вместо :param проблема решилась.
Всем спасибо, отдельно - sniknik ©


Vlad Oshin   (2008-10-06 09:24:00) [5]


> > Непонятно зачем ты вообще устраиваешь пляски с бубном
> вокруг
> > параметров - чем не устроила стандартная схема ?
>
>
> Тем, что у меня вообще не оконное приложение. И в дизайн-
> тайме я ничего выставить не могу.

а добавить   Unit1 in 'Unit1.pas' {DataModule1: TDataModule};
и накидать чего хочешь?


MsGuns   (2008-10-06 09:10:00) [6]

>Я бы предпочел, если честно использовать "нативные" компоненты (компоненты "прямого >доступа"), а не ADO.

Толкать грузовик вручную вместо того, чтобы просто запустить мотор и поехать ?


sniknik   (2008-10-06 08:48:00) [7]

> и какие из них кажутся Вам наиболее удачными?
ни одни.
самые удачные, гибкие, и с максимумом возможностей (и потому самые сложные) это ADO.
было время тестировал парочку "прямого доступа", и ничего особого, кроме ограниченного функционала того же ADO в них не нашёл. другое дело работать с ними было попроще, реализована всего одна схема работы. но изучать/использовать их не рекомендовал бы, зачем изучать сурогат, когда есть оригинал? и нафига потом переучиваться, когда понадобится возможность которая есть в ADO, но которая проигнорирована в этих "найтивных"?


Германн   (2008-10-06 02:01:00) [8]

<offtop>
Вот после таких веток и думаешь, почему все, кому не лень,  "столь грязно" ругают Парадокс?
</offtop>
:)


kaif   (2008-10-06 01:36:00) [9]

2 sniknik ©   (05.10.08 14:26) [28]
Спасибо за ответ.
Таким образом все "нативные" компоненты Delphi для MSSQL работают через COM-объекты MDAC, если я правильно понял.
Я бы предпочел, если честно использовать "нативные" компоненты (компоненты "прямого доступа"), а не ADO.
Какие конкретно (платные и бесплатные) существуют и какие из них кажутся Вам наиболее удачными?


sniknik   (2008-10-05 14:26:00) [10]

> А что, MSSQL не имеет разве своей клиентской dll
имеет конечно, прямо в виндовс встроенную (MDAC), но не в том виде что у IB/Firebird, не отдельная распространяемая вместе с программой, а устанавливаемый в винду пакет COM обьектов.

> А с чем же тогда BDE драйвер работает?
х.з. может с dblib, может что то своё, но строго говоря он уже давно не работает ... поддержка с версии MSSQL 6,5 прекращена.
только вариант с BDE + ODBC ещё "дышит", а  драйвера ODBC сейчас тоже входят в MDAC и не поймешь, кто там кого использует. вот для dbase/paradox очевидно, их драйвера ODBC используют jet (т.е. OLEDB провайдер.).


kaif   (2008-10-05 02:25:00) [11]

MsGuns ©   (04.10.08 22:15) [26]
>Например, логика работы самого MSSQL (например, триггеров и >взаимодействия с ними внешних каскадных ключей) сильно отличается от >логики IB Или ORACLE.

В чем "сильность" ?


В том, что триггеры срабатывают послепроверок на ссылочную целостность. И в том, что они все BEFORE. Плюс они срабатывают не на каждую запись, а на всю командув целом. Например, IB при множественной вставке insert into ... select ... from ... сработает столько раз, сколько вставляется строк. А триггер MSSQL - единожды. На самом деле для задач, орудующих большими массивами это удобно.
Разумеется, отсутствие suspend меня сразу смутило. Но зато MSSQL позволяет очень лихо (и главное быстро, и это принятый прием) создавать временные таблицы внутри хранимых процедур и возвращать их набор.

Недостаток suspend восполняет функция, возвращающая тип данных TABLE. По крайней мере в MSSQL 2005 (а возможно и в 2000) это работает отменно, я попробовал.

Неприятным открытием для меня стало то, что если удаление строк делается в триггере, то каскадный внешний ключ просто не сработает. Здесь я вижу кривизну самой архитектуры - естественную плату за то, что триггер срабатывает единожды и срабатывает BEFORE.

Мне кажется, что многие из твоих проблем в связке ADO+MsSQL от "гридного" редактирования

Я не злоупотребляю гридным редактированием. Но считаю полный отказ от DATA AWARE компонентов другой крайностью. Нафиг тогда вообще это все было придумано? В IB у меня с этим проблем нет. Я же не вытягиваю таблицы на клиент в IBTable и не редактирую их там наивно в сетках.
Мне просто кажется естественным, когда юзер может в сетке подправить количества в нескольких строках накладной, содержащей в среднем 20 строк, не прибегаякаждый раз к вызову диалогового окнадля этой цели. Если есть проблемы с медленной отправкой строк на сервер в процессе такого редактирования (если честно, в IB таких проблем обычно просто нет), то можно использовать CachedUpdate := True и дело с концом - в ApplyUpdates я полностью управляю отсылкой данных так, как пожелаю.

Это ведь архитектура самого Delphi - работа с данными в Data Aware Controls. Я знаю людей, которые все запихивают в StringGrid только ради того чтобы не держать запрос открытым. Ну и зачем это? А если серверу все же нужно знать о необходимости блокировки? Я вижу, что в MSSQL Это весьма может быть актуальным.

sniknik ©   (04.10.08 21:38) [25]
> А вот реализация работы с ним через ADO-компоненнты в Delphi
думаешь вот эта вот запись "не туда" реализована на уровне дельфевской обертки? ;) ... нет, это чисто ADO-шная вещь, сделай все на обьектах ADO, помучится тоже самое.


Это я уже понял. Я сегодня внимательно рассмотрел модуль ADODB.PAS. :(
Но мне все же видится, что встроить 4 команды, как ты предложил, вполне реально. Наверняка можно заставить ADO не делать запрос "живым".

К сожалению в сети не так уж много литературы по ADO Delphi. И написано везде одно и то же. Ты говоришь о ссылках на статьи на Королевстве. Я тогда посмотрел все, что мне давали. Unique Table я так и не смог задействовать. Может быть времени не хватило. Но времени у меня и не было совершенно. И меня очень разражали проблемы на каждом шагу. Впрочем, это мои проблемы.

В пользу ADO (я работал через него с dBase и Access) могу сказать, что мне нравится его скорость Fetch-а, "гладкость" работы, экономность (как мне показалось) в отношении ресурсов и довольно развитая поддержка SQL в локальных вариантах (выборки из dBase). Например если бы не ADO, я бы вообще не знал как мне (иначе, чем разбирая dBase файл руками) считать двоичные данные из строковых полей (был такой раньше способ оптимального запихивания чисел в DBF). ADO позволил мне тогда получить эти данные в SELECT-е как cast(... as VarBinary()) или что-то в этом духе, может неверно помню, но работал такой typecast отлично. Никакие иные средства не позволяли (BDE, например) получить в строках символы после символа 0, так как они понимали 0 как конец строки (как и принято в Windows). А запиханные двоично числа в строки могли, разумеется, содержать нулевые байты. Поэтому я и говорю, что к OLEDB как таковому у меня особых нареканий нет.

А что, MSSQL не имеет разве своей клиентской dll ? А с чем же тогда BDE драйвер работает? Или он напрямую через TCP/IP  с сервером общается?


MsGuns   (2008-10-04 22:15:00) [12]

>kaif ©   (04.10.08 21:01) [24]
>А вообще это неплохая идея.

Это правильнаяидея - явно писать запросы на изменения в несколькотаблиц, не полагаясь на "ителлект" оберток. А если уж полагаешься, то подстраивайся под них, а не пытайся бороться с ними. И не возмущайся на их "кривость", если они ведут себя "не так".

>И больше не иметь никаких проблем.

ИМХО, у тебя проблемы только потому, что ты сам их настойчиво выискиваешь

>Например, логика работы самого MSSQL (например, триггеров и >взаимодействия с ними внешних каскадных ключей) сильно отличается от >логики IB Или ORACLE.

В чем "сильность" ?

>Но я заценил MSSQL, поработав с ним.

Не ты один. Однако он весьма сложен в администрировании. В частности весьма трудно управлять логом (и вообще он, ИМХО, сделан совершенно идиотически, в связи с чем больше напоминает мусорную свалку, чем "журнал". Особенно когда надо в нем что-то найти).
Также неудобно реализованы копирования и восстановления. Нет возможности хранения скриптов и расширенных комментариев как в ИБ. Еще одна дурость - невозможность селекта из хранимок, а таже существенные ограничения при написания функций.
Еще мне не понравилось отсутствие такого удобного средства, как suspend, что приводит к тому, что сервер не начинает отсылку пока не выберет все. Иногда это приводит к излишней загрузке сети и ненужному ожиданию на клиенте.

Единственное СУЩЕСТВЕННОЕ отличие мсскл от ИБ - это абсолютно иной механизм транзакций. Вот к этому, действительно, надо приспособиться и привыкнуть.

>А вот реализация работы с ним через ADO-компоненнты в Delphi  нравилась мне все меньше и меньше, пока не разонравилась вовсе.

Что же касается ADO - то я не знаю другого такого же по гибкости и "комфортности" набора компонент. Во всяком случае по сравнению с IBX.

И последнее. Мне кажется, что многие из твоих проблем в связке ADO+MsSQL от "гридного" редактирования. Если ты сможешь заставить себя навсегда от него отказаться (имеется в виду не вообще от правки в сетках с т.зр.пользователя, а именно от редктирования самого датасета, "напрямую" связанного с таблицами БД), то проблем у тебя существенно поубавится.


sniknik   (2008-10-04 21:38:00) [13]

> Может и стоит реализовать как-нибудь свой TKaifADODataSet
наверняка уже такой есть, фанатов Fib-ов/пересаживающихся с IB, хватает, неужели мне первому это в голову пришло? вряд ли.

> А вот реализация работы с ним через ADO-компоненнты в Delphi
думаешь вот эта вот запись "не туда" реализована на уровне дельфевской обертки? ;) ... нет, это чисто ADO-шная вещь, сделай все на обьектах ADO, помучится тоже самое.


kaif   (2008-10-04 21:01:00) [14]

sniknik ©   (04.10.08 14:45) [23]
нравится логика с 4 отдельными запросами, что мешает добавить в ADO 4-ре ADOCommand и прописать в них такие же?


А вообще это неплохая идея. Может и стоит реализовать как-нибудь свой TKaifADODataSet, прямого наследника TDataSet с 4-мя командами и парсером параметров, который не вызывается вторично, если коллекция параметров была создана дизайн-тайм.

И больше не иметь никаких проблем.

Дело все же я думаю не в иной логике. Я готов привыкнуть к иной логике. Например, логика работы самого MSSQL (например, триггеров и взаимодействия с ними внешних каскадных ключей) сильно отличается от логики IB Или ORACLE.
Но я заценил MSSQL, поработав с ним.
Это действительно весьма хороший и производительный сервер, и с ним приятно работать. И он мне быстро понравился, несмотря на иную логикупочти во всем.
А вот реализация работы с ним через ADO-компоненнты в Delphi  нравилась мне все меньше и меньше, пока не разонравилась вовсе.

С уважением.


sniknik   (2008-10-04 14:45:00) [15]

> исключительно лишь для того чтобы отобразить его в сетке
а ADO про это знает? что ты вставил в привязанную таблицу значения исключительно "на посмотреть".
про то и говорил ([20]), не надо туда писать, надо прописать код товара только основной таблице, и при записи сработает (если прописаны Resync Command, Unique Table) "подтяжка" значений ("суррогатный id товара, наименование товара") из дополнительной, для этой записи.
и все, только чуть чуть другая логика.  

> Впрочем, если Вам нравится то, как "ADO думает за нас", то, как говорится, на вкус и цвет...
какая разница нравится или нет? оно так есть, и все. хочешь пользоваться - изучай "механизм", как он работает. и следуй его логике. или пиши свою, но на основании этой уже существующей.
нравится логика с 4 отдельными запросами, что мешает добавить в ADO 4-ре ADOCommand и прописать в них такие же?
хочешь "все одном"? - сделай это компонентом.

> Тогда спор просто бессмысленен.
а кто спорит то?


kaif   (2008-10-04 13:45:00) [16]

2 sniknik ©   (04.10.08 12:34) [20]

То, что при update полей одной таблицы update вставки во вторую не происходит, это я и тогда обнаружил. Странно было бы, если бы это было не так. Собственно, а что вставлять?

Проблема совершенно в другом.

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

Мне неохота возвращаться к тем исследованиям. Вот куски кода, которые я закомментировал, пытался чего-то добиться. Результат был нулевым:

//  qryDetail.Properties['Unique Table'].Value := 'ORDER_ITEMS';
//  qryDetail.Properties['Update Criteria'].Value := adCriteriaUpdCols;
//  adCriteriaKey, adCriteriaAllCols, adCriteriaUpdCols

Сделаем проще. Вот примерно то, как я решаю подобную задачу в IBX (опустим лишнее, будем считать, что у нас всего одна накладная):

IBDataSet1.SelectSQL.Text = 'select n.id, g.good_id, g.name, n.quantity from goods g, nakl n where n.good_id = g.id';
IBDataSet1.ModifySQL.Text = 'update nakl set good_id = :good_id, quantity = :quantity where n.id = :old_id';
IBDataSet1.DeleteSQL.Text = 'delete from nakl where id = :old_id';
IBDataSet1.RefreshSQL.Text = 'select n.id, g.good_id, g.name, n.quantity from goods g, nakl n where n.good_id = g.id and n.id = :id';

То есть у меня имеется 4 команды. И полная свободасделать именно то, что мне нужно, без недоразумений и гаданий. Единственное, чего мне не дает IBX - мультитабличной вставки. Ну и слава богу. К чему мне этот страшный сон?

И так вариантов поведения, которое разработчику может понадобиться  слишком много: и апдейты с использованием всехполей в WHERE, и апдейты с использованием только измененных, и апдейты с опорой на ключевые поля. И апдейты не всех измененных юзером в сетке полей, а лишь полей, указанных в SET ... = ..., не трогая иные поля. Да мало ли что захочет разработчик? Например в ModifySQL я вообще часто вписываю вызов хранимой процедуры.
Вот дали разработчику 4 команды и известно, что это именноте команды и толькоте команды, что отправятся на сервер. И ничего такого за кулисами, что бы за него додумывали.

И не только IBX Так устроены.

Впрочем, если Вам нравится то, как "ADO думает за нас", то, как говорится, на вкус и цвет... Тогда спор просто бессмысленен.


sniknik   (2008-10-04 12:35:00) [17]

> Parameters[0], Parameters[1], можно присвоить имена параметрам.
после того как создашь пожалуйста, а пока их нет... ошибка будет (вне списка).


sniknik   (2008-10-04 12:34:00) [18]

> О как...
а ты как думал? :)
раз уж не пользуешься тем что дядя борланд написал, читай справку "оригинала".

> Если кто-нибудь приведет конкретное решение с Unique Table с примером работающего кода
я тут проверил... даже Unique Table не нужно (вернее нужно но не для этого), заявленная проблема "вставки куда не просят" -
> он пытается все эти запросы сам как-то сгенерировать, в результате он, естественно, пытается вставлять данные не только в таблицу накладных,
> но и наименования товаров в справочник товаров
вовсе и не проблема (вернее ADO/обертка к ней не причастны)... т.к. вставки не происходит если не редактировать значения второй связанной таблицы
т.е. пробовал запрос (отдаваемые на редактирование в грид поля выделены)
SELECT m.ID, m.mInt,m.mName,d.ID,d.mID, d.dInt,d.dNameFROM Main m LEFT JOIN Detail d ON m.ID=d.mID
так вот если ввести значения всем полям, действительно идет вставка в обе таблицы (что естественно, раз ввели, или эти данные потеряются),
если же вводить только в поля первой таблицы т.е. - m.mInt,m.mName, вставки во вторую нет, даже без Unique Table.
т.е. получается что ты там где то задаешь значения второй таблице ("просишь о вставке данных"), а после удивляешься попытке сохранить эти данные...
> хотя они там уже присутствуют и защищены у меня уникальным ключом.
а вот тут уже нужна Unique Table, т.к. эти уже присутствующие данные необходимо отображать (?), типа ввели код товара в накладную и по нему "подтянулось" его значение из справочника, вот для такой "подтяжки" есть Resync Command, а она работает в паре с Unique Table (вот и ее необходимость, и потом без нее удаление будет происходить тоже обоих связанных записей).
но вообще это все есть в статьях на королевстве (блин вот почему их не было когда я это изучал?), ссылки куда тебе вроде давали (да и так найти не проблема).


Anatoly Podgoretsky   (2008-10-04 12:20:00) [19]

Parameters[0], Parameters[1], можно присвоить имена параметрам.


Johnmen   (2008-10-04 12:01:00) [20]


> О как...

Ага, именно так, как описано в справке...:)


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо