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

Вниз

ADO и MS SQL - посоветуйте хорошую ссылку   Найти похожие ветки 

 
Ega23 ©   (2008-09-09 16:00) [80]


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


Locktype:=ltBatchOptimistic, вроде так пишется.


 
kaif ©   (2008-09-09 16:03) [81]

2 sniknik ©

Вот это работает. Это тот же самый текст, что "и для тупых", что не работал. Отличие я выделил жирно.

Теперь объясни.

procedure TSimpleReferenceForm.Button1Click(Sender: TObject);
var
P: TParameter;
begin
with TADOCommand.Create(nil) do
try
  Connection := MainData.Connection;

  P := Parameters.AddParameter;
  P.DataType := ftString;
  P.Direction := pdInput;
  P.Name := "NAME";

  P := Parameters.AddParameter;
  P.DataType := ftInteger;
  P.Direction := pdOutput;
  P.Name := "ID";

  CommandText :=
     "BEGIN TRAN"#13+
     "INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)"#13#10+
     "SELECT :ID = SCOPE_IDENTITY()"#13+
     "COMMIT TRAN";

  Parameters.ParamByName("NAME").Value := "Дядя Вася 12";

  Execute;
  ShowMessage(IntToStr(Parameters.ParamByName("ID").Value));
finally
  Free;
end;
end;


 
Anatoly Podgoretsky ©   (2008-09-09 16:09) [82]

> kaif  (09.09.2008 16:03:21)  [81]

Маленький совет, лучше не использовать #13#10 при объединение литералов, а добавлять пробел или в начале каждого литерала или в конце

" BEGIN TRAN"+
"   INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)"+
"   SELECT :ID = SCOPE_IDENTITY()"+
" COMMIT TRAN";


Меньше будет неожиданных проблем.


 
kaif ©   (2008-09-09 16:20) [83]

Между прочим такой вот код не работает.

procedure TSimpleReferenceForm.AddRecord(const AName: string);
var
 P: TParameter;
begin
 with TADOCommand.Create(nil) do
 try
   ParamCheck := True;
   Connection := MainData.Connection;
   CommandText :=
                  "SET NOCOUNT ON"#13+
                  "INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)"#13+
                  "SELECT :ID = SCOPE_IDENTITY()";

   Parameters.ParamByName("ID").Direction := pdOutput;
   Parameters.ParamByName("NAME").Value := AName;
   Execute;
   self.LastID := Parameters.ParamByName("ID").Value;
 finally
   Free;
 end;
end;


Причем ошибка возникает совершенно иного сорта. "Параметр задан неверно". Причем только если в тексте запроса две команды. Для одиночной команды проблем нет.

Для того чтобы он заработал нужно либо до присвоения текста CommandText создать рантайм все параметры, а после присвоения подправить Direction параметра с именем ID, либо же после присвоения CommandText сначала все параметры (их там 2 шт к этому моменту - я проверил) очистить методом Clear и заново создать рантайм, присвоив нужные Direction.

Я считаю это совершеннейшим багом.
У остальных может на этот счет быть свое собственное мнение.


 
kaif ©   (2008-09-09 16:24) [84]

Всем спасибо.


 
sniknik ©   (2008-09-09 16:29) [85]

> Вот это работает.
упс... точно работает. не ожидал.

> Теперь объясни.
не могу. буду смотреть.


 
Anatoly Podgoretsky ©   (2008-09-09 16:29) [86]

> kaif  (09.09.2008 16:24:24)  [84]

Это значит, что прощаешься? :-)


 
sniknik ©   (2008-09-09 16:31) [87]

> Причем ошибка возникает совершенно иного сорта. "Параметр задан неверно".
тип интеджер добавь, возможно проблема в этом.


 
kaif ©   (2008-09-09 16:41) [88]

Вот результаты моих исследований.

1. Парсер параметров ADO в определенных ситуациях портит значения Direction, но не портит значения типов (DataType) параметров, которые были установлены до присвоения CommandText.
2. Типы он определять в этих ситуациях сам не может, но и не портит, если они присвоены заранее. А вот Direction - портит, даже если заранее установлено верно.
3. Этот парсер ошибается не всегда, и лишь в каких-то случаях.

Рекомендации:
Можно положиться на то, что коллекцию параметров (количество и имена) после присовения CommandText парсер создаст правильно. Очищать их необязательно. Но при любых проблемах (если таковые возникли), присваивать как Direction, так и DataType принудительно после присвоения CommandText еще раз.

То есть вот минимальный текст:

 with TADOCommand.Create(nil) do
 try
   Connection := MainData.Connection;
   CommandText :=
                  "SET NOCOUNT ON "#13+
                  "INSERT INTO GOODS(GOOD_NAME) VALUES (:NAME)"#13+
                  "SELECT :ID = SCOPE_IDENTITY()";

   Parameters.ParamByName("NAME").DataType := ftString;
   Parameters.ParamByName("NAME").Direction := pdInput;
   Parameters.ParamByName("ID").DataType := ftInteger;
   Parameters.ParamByName("ID").Direction := pdOutput;

   Parameters.ParamByName("NAME").Value := AName;
   Execute;
   Result := Parameters.ParamByName("ID").Value;
 finally
   Free;
 end;


 
kaif ©   (2008-09-09 16:42) [89]

Anatoly Podgoretsky ©   (09.09.08 16:29) [86]
> kaif  (09.09.2008 16:24:24)  [84]

Это значит, что прощаешься? :-)


Ну я еще появлюсь. Вопросов еще много возникнет.
:)


 
Медвежонок Пятачок ©   (2008-09-09 16:47) [90]

по моим наблюдениям портит и то и другое.
я ввел командтекст с set :id = @@identity, пошел в редактор параметров
там автоматом появился инпут параметр типа стринг.
поменял его на аутпут интегер, выполнил запрос.

поменял командтекст на select :id = @@identity, пошел в редактор.
снова инпут стринг параметр.

ps метаданные сервера были доступны редактору в обоих случаях.

или после первой правки типов у меня не тот случай, когда параметр создан заранее?

надо бы глянуть в дфм что там


 
MsGuns ©   (2008-09-09 16:48) [91]

>> не по одной записи, а несколькими логически связанными.
>Locktype:=ltBatchOptimistic, вроде так пишется.

Эге ж, а теперь объясните мне пжлст каким раком мне указывать каждый раз размеры ентого самого "пакета", причем для разных таблиц - свой (при редактировании по технологии "мастер-детал") ?


 
Ega23 ©   (2008-09-09 17:05) [92]


> Эге ж, а теперь объясните мне пжлст каким раком мне указывать
> каждый раз размеры ентого самого "пакета", причем для разных
> таблиц - свой (при редактировании по технологии "мастер-
> детал") ?


Блин. Как-то можно было. Дома попытаюсь старые исходники поднять.
Но что-то такое делал.


 
kaif ©   (2008-09-09 17:07) [93]

2 sniknik ©

В любом случае я благодарен тебе за две вещи:

1. За то, что именно ты подсказал мне идею использовать SELECT :ID = или SET :ID = для того чтобы попытаться вернуть IDENTITY в качестве выходного параметра при вызове методами ExecSQL или Execute,  а не в виде результирующего набора методом Open. Так как использование метода Open для вставки данных делает текст программы некрасивым.

2. За то, что ты подсказал мне использовать ADOCommand.Execute вместо ADOQuery.ExecSQL.

Что касается парсинга параметров, то очевидно, что парсер ADO вряд ли в состоянии определять их типы, смотря в текст команды. Неприятно поразило то, что он может запортить их Direction. Я не привык к такому поведению компонентов, например, IBX так себя не ведут. Если Direction параметра в дизайн тайме выставлен, IBX не пытается его менять. Если что не так, он просто даст ошибку времени выполнения, а не будет вводить в заблуждение разработчика. Так что такое поведение ADO не назовешь стандартным. Что и вызвало массу затруднений, и похоже не только у меня. То, что помещение вызова BEGIN TRANS что-то изменило, возможно, просто случайность. Если разборщик пытается изменить Direction параметров, но при этом глючит, то тут можно ожидать все что угодно.

Еще я благодарен всем остальным участникам за полезную информацию разного рода, которую я по ходу почерпнул.

Что касается вопроса транзакций в ADO с сMSSQL, то я думаю открыть для этого отдельную ветку.


 
sniknik ©   (2008-09-09 17:14) [94]

> Теперь объясни.
с транзакцией сервер почемуто не возвращает коллекцию параметров, почему не знаю...

код в ADODB
procedure TADOCommand.AssignCommandText(const Value: WideString; Loading: Boolean);

....
           { Retrieve additional parameter info from the server if supported }
           Parameters.InternalRefresh;
           { Use additional parameter info from server to initialize our list }
          if Parameters.Count = List.Count then
             for I := 0 to List.Count - 1 do
             begin
               List[I].DataType := Parameters[I].DataType;
               List[I].Size := Parameters[I].Size;
               List[I].NumericScale := Parameters[I].NumericScale;
               List[I].Precision := Parameters[I].Precision;
               List[I].Direction := Parameters[I].Direction;
               List[I].Attributes := Parameters[I].Attributes;
             end
....


в Parameters.Count при запросе с транзакцией 0 (это список полученный с sql сервера), ясно что выделенное условие не выполнится т.к. в List.Count 2
а до этого в List распарсивается запрос (создаются параметры) и (в выделенном) переносятся/сохраняются значения, если они есть (сравнение по имени).
     NativeCommand := List.ParseSQL(Value, True);
     { Preserve existing values }
     List.AssignValues(Parameters);


вот, зачем так сделано х.з. но твои параметры остаются только потому что сервер ничего при таком запросе не вернул. если бы вернул, то действовала бы его инициализация параметров.

и это в общем-то ничего не меняет в правиле, назначать свои значения только после инициализации. во избежание сюрпризов.


 
sniknik ©   (2008-09-09 17:18) [95]

> Эге ж, а теперь объясните мне пжлст каким раком мне указывать каждый раз размеры ентого самого "пакета", причем для разных таблиц -
> свой (при редактировании по технологии "мастер-детал") ?
"детайл" задавай запросом. а не по привычке как у таблиц в BDE.


 
sniknik ©   (2008-09-09 17:21) [96]

> 3. Этот парсер ошибается не всегда, и лишь в каких-то случаях.
судя по всему изза двойственности в определении, удалось получить с сервера или нет, лучше бы было меньше "авто" зато больше ясности (не удалось - значит не определено. и никаких гвоздей!).


 
kaif ©   (2008-09-09 18:48) [97]

2 sniknik ©

Вот теперь все стало ясно!
Спасибо за труды.

Я подозревал, что парсер в какой-то момент спрашивает параметры у сервера, но в код VCL за подробностями не лез.

Значит ошибка все же не в парсере ADO Delphi.
Просто сервер что-то не то возвращает в ситуации "SELECT :ID = " или провайдер не то доставляет.


 
sniknik ©   (2008-09-09 19:51) [98]

> Я подозревал, что парсер в какой-то момент спрашивает параметры у сервера, но в код VCL за подробностями не лез.
зачем подозревать? открытым текстом было сказано
sniknik ©   (09.09.08 11:42) [31]
> Там даже не баги, а урезанная реализация некоторых возможностей.
имел в виду именно баги, например был баг при внесении запроса частями через ADOQuery.SQL.Add(), чего по логике ADO делать было нельзя т.к. при внесении запроса определяются какието параметры, и определяются они на стороне сервера куда передается запрос, часть же всегда неправильна... кстати именно поэтому нужно подключение при разработке, можно конечно и без него и руками все устанавливать, толко основные претензии по этому поводу как раз в том что оно чегото не делает, а вот то что программист должен обеспечить какието условия для этого, это игнорируется.

думаешь я это просто так ляпнул, не подумавши? хотя, видимо так ты и думаешь, судя по ответу на это в [33].

> Просто сервер что-то не то возвращает в ситуации "SELECT :ID = " или провайдер не то доставляет.
наоборот, в этом случае он возвращает все, а вот в варианте с закрытием транзакцией почемуто не определяет не то что типов, а вообще параметров не распознает.


 
kaif ©   (2008-09-09 20:14) [99]

У тебя не иссякает желание говорить в таком тоне.
Хорошо.
Значит я тебя неправильно понял.

Но ты неверно говоришь здесь:

наоборот, в этом случае он возвращает все

Все-то он, может, и возвращает (в смысле правильное количество параметров), вот только Direction возвращает кривое для конкретно параметра ID. Если было бы не так, не пришлось бы столько мучиться из-за простой вещи.



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

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

Наверх




Память: 0.65 MB
Время: 0.013 c
11-1200515589
Vinum
2008-01-16 23:33
2009.05.17
как скопировать текст в буфер


2-1238664318
D@nger
2009-04-02 13:25
2009.05.17
принадлежит ли дата периоду?


2-1238935538
random(1024)
2009-04-05 16:45
2009.05.17
Как из компонента TWebBrowser распечатать страничку...


3-1220966118
Demo_nik
2008-09-09 17:15
2009.05.17
Определение координат ячейки


8-1194337984
Navuh
2007-11-06 11:33
2009.05.17
Работа с огромными изображениями (80.000*42.000)





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