CRUD на хранимках

Обсуждение возникших проблем, предложений и ошибок UniDAC компонентов
WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

CRUD на хранимках

Сообщение WildFrag » Пн 29 апр 2013 11:46

Подскажите пожалуйста, я пытаюсь сделать так чтобы набор данных полностью работал через ХП.
Я создал хранимку для Insert, она вставляет значение в таблицу с автоинкрементом, а последней строкой возвращает только что вставленную строку полностью, вместе с ключевым полем и всеми остальными полями, посути таже команда что используется для SELECT но возвращается только одна строка.
Я бы хотел использовать эти возвращенные данные для того чтобы обновить на клиенте датасет в который я вставил данные, так как фактически мне придет не только значение ключевого поля, но и еще рад полей которые автоматически рассчитались на сервере.
Как я могу это сделать?

Alexp
Devart Team
Сообщения: 349
Зарегистрирован: Пн 27 дек 2010 10:34

Re: CRUD на хранимках

Сообщение Alexp » Вт 30 апр 2013 09:56

Добрый день,

Пожалуйста, уточните с какими БД Вы работаете?

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Вт 30 апр 2013 12:48

Конкретно сейчас MSSQL 2008.

Набросал примерчик SELECT

Код: Выделить всё

CREATE PROCEDURE [dbo].[SchetSelect] (
	@KOD INT
)
AS
BEGIN
	SELECT 
		Schet.Kod,
		KodBaseLPU,
		God,
		Mes,
		NSchet,
		DSchet,
		SummaVyst,
		VidPom,
		CASE VidPom 
			WHEN 1 THEN 'стац'
			WHEN 2 THEN 'д.стац'  
			WHEN 3 THEN 'пол'  
			WHEN 4 THEN 'стом'
			WHEN 5 THEN 'с.п.'		
			ELSE '-' 
		END as VidPomName,
		Dict_Ref_BaseLPU.Naim
    FROM 
		Schet
    JOIN Dict_Ref_BaseLPU ON 
		Dict_Ref_BaseLPU.Kod = Schet.KodBaseLPU
	WHERE 
		((@KOD is NULL) OR
		(Schet.Kod=@KOD))
END
А вот так выглядит INSERT, пример не совсем реальный, просто для понимания принципа

Код: Выделить всё

CREATE PROCEDURE [dbo].[InsertSchet] (
	@NSchet nvarchar(20),
	@SummaVyst numeric(15, 2)
)
AS
BEGIN
	SET NOCOUNT ON;
	
	DECLARE @KOD int
	select @KOD=MAX(Kod)+1 from Schet
	
	INSERT INTO Schet (
		Kod,
		KodBaseLPU,
		God,
		Mes,
		NSchet,
		DSchet,
		SummaVyst,
		VidPom )
	VALUES (
		@KOD,
		1,
		CONVERT(int, YEAR(GETDATE())),
		CONVERT(int, MONTH(GETDATE())),
		@NSchet,
		GETDATE(),
		@SummaVyst,
		3)
		
	exec dbo.SchetSelect @KOD


END

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: CRUD на хранимках

Сообщение AndreyZ » Пт 10 май 2013 14:26

Извините за задержку с ответом.
Для возвращения данных на клиент Вы можете использовать выходные параметры хранимых процедур. Например:

Код: Выделить всё

begin
  MSStoredProc1.StoredProcName := 'selecttest';
  MSStoredProc1.SQLInsert.Text := 'execute inserttest :id out, :dt out, @txt=:txt';
  MSStoredProc1.Options.ReturnParams := True;
  MSStoredProc1.PrepareSQL;
  MSStoredProc1.Open;
  MSStoredProc1.Append;
  MSStoredProc1.FieldByName('txt').AsString := 'test';
  MSStoredProc1.Post;
end;
, где test это следующая таблица:

Код: Выделить всё

CREATE TABLE test(
  id INT NOT NULL,
  dt DATETIME NULL,
  txt VARCHAR(50) NULL,
  CONSTRAINT PK_test PRIMARY KEY (id)
) ON [PRIMARY]
, selecttest и inserttest это следующие хранимые процедуры:

Код: Выделить всё

CREATE PROCEDURE selecttest
AS 
SELECT * FROM test

Код: Выделить всё

CREATE PROCEDURE inserttest
  @id  INT      OUT,
  @dt  DATETIME OUT,
  @txt VARCHAR(50)
AS
BEGIN
  SELECT @id = max(ID) + 1 FROM test;
  SET @dt = getdate();
  INSERT INTO test(id, dt, txt) VALUES (@id, @dt, @txt);
END

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Вс 12 май 2013 10:40

Андрей, спасибо за пример

Реализация на OUT параметрах в принципе неплоха если делаешь проект с нуля.
У нас к сожалению сложилась ситуация когда хочется перевести клиента с Ado+Ehlib на Unidac+DevEx(Grid), не трогая весь функционал работающий на хранимках.
Есть ли возможность обработать курсор, возвращенный с сервера при процедуре вставки в БД?
Т.е именно в той реализации которую я показал?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: CRUD на хранимках

Сообщение AndreyZ » Пн 13 май 2013 13:52

На данный момент такой возможности в UniDAC нет. Приведите пожалуйста пример демонстрирующий данный подход при использовании ADO.

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Вт 14 май 2013 06:32

Это скорее фишка именно Ehlib
там существует свой собственный memtable и драйвера доступа к разным БД, посути драйвер представляет собой TUpdateSQL. Причем довольно гибкий, например можно сказать что delete или update возвращают датасет, а не просто делают exec команды написанной в DeleteSQL и UpdateSQL. Для перехвата датасета возвращаемого с сервера при этих операциях есть эвент в котором я получаю датасет, возвращенный с сервера при выполнении команды update и т.д.
Поэтому я могу из возвращенного датасета спокойно поправить memtable без реального его редактирования. Вот пример вставки договора, обратно отваливается датасет из которого я использую автоинкрементарное поле dogovor_id и рассчитанное на сервере hourcost.

Код: Выделить всё

procedure TDM.drvDogGetBackUpdatedValues(DataDriver: TADODataDriverEh;
  MemRec: TMemoryRecordEh; Command: TADOCommandEh; ResDataSet: TDataSet);
begin
  if Assigned(ResDataSet) then
  begin
    MemRec.DataValues['dogovor_id', dvvValueEh]:= ResDataSet.FieldByName('dogovor_id').Value;
    MemRec.DataValues['hourcost', dvvValueEh]:= ResDataSet.FieldByName('hourcost').Value;
  end;
end;
Мне очень нравится данный подход, гибкость того что я могу сделать просто великолепная.
Единственная проблема это то что драйвер по сути транслирует все команды в ADO, а затем загружает результат выполнения в memtable. Это влечет за собой проблемы при банальном селекте, сначала в памяти создается TADOQuery, он открывается, а затем все копируется из TADOQuery->MemTable. И вот эта операция копирования ой какая не быстрая, я столкнулся с тем что у меня датасет на 10к записей с сервера загружается за 10сек, а затем еще 40с копируется в memtable

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: CRUD на хранимках

Сообщение AndreyZ » Вт 14 май 2013 14:03

UniDAC не имеет такую функциональность. Вы можете оставить свое предложение на нашей UserVoice странице: http://devart.uservoice.com/forums/1046 ... components . Если Ваше предложение наберет много голосов от других пользователей, мы реализуем его.

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Пт 08 май 2015 17:49

В версии 6.0.1 пример на OUT параметрах от AndreyZ не работает. На debug видно что не смотря что в тексте sql запроса на insert параметры заданы как out, в списке параметров передаваемых на сервер они заданы как in и соответственно возвращенные с сервера знаения не обрабатываются и не появляются в датасете.
В чем может быть дело?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: CRUD на хранимках

Сообщение AndreyZ » Вт 12 май 2015 14:09

Для ранее указанного мной примера, кроме установления свойства TUniStoredProc.Options.ReturnParams в True, укажите, что параметры с именами 'id' и 'dt'(из свойства TUniStoredProc.SQLInsert.Tex) являются OUT параметрами. Для этого, в событии TUniStoredProc.BeforeUpdateExecute, задайте свойству параметра TDAParam.ParamType значение ptOutput. Например:

Код: Выделить всё

procedure TForm1.UniStoredProc1BeforeUpdateExecute(Sender: TDataSet;
  StatementTypes: TStatementTypes; Params: TDAParams);
begin
  if stInsert in StatementTypes then begin
    Params.ParamByName('id').ParamType := ptOutput;
    Params.ParamByName('dt').ParamType := ptOutput;
  end;
end;

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Вт 12 май 2015 19:51

А это нормальное поведение или баг? Просто раньше необходимости в ручной установке типа параметра небыло необходимости. Парсер сам брал SQL запрос и параметры out делал как ptOutput.
Т.е будет ли это поправлено или это теперь нормальное поведение компонента и ничего не изменится?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: CRUD на хранимках

Сообщение AndreyZ » Чт 14 май 2015 14:10

Это корректное поведение и мы не меняли его много времени. Пожалуйста, уточните номер версии UniDAC, в которой out параметрам автоматически устанавливался тип ptOutput.

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Чт 14 май 2015 15:13

Ну точно не скажу, но судя по дате сообщения версия unidac доступная 10 мая 2013 года. В вышеприведенном примере кстати тоже ничего не упоминается о ручной установке out параметров, т.е на момент написания примера out параметры в тексте запроса работали без ручной настройки.
Да и тогда вообще непонятно зачем в запросе параметры помечать как out если перед запуском мы их все равно правим руками.

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: CRUD на хранимках

Сообщение AndreyZ » Пн 18 май 2015 13:45

В версии 5.0.1 и последней версии, данное поведение UniDAC не отличается.

В SQL запросе для выполнения хранимой процедуры необходимо указывать типы параметров out, чтобы SQL Server вернул значения для этих параметров запроса.

Задавать свойству TDAParam.ParamType значение ptOutput необходимо, чтобы UniDAC вернул значения для этих параметров датасета из параметров запроса.

WildFrag
Сообщения: 22
Зарегистрирован: Пн 29 апр 2013 11:41

Re: CRUD на хранимках

Сообщение WildFrag » Вт 19 май 2015 07:37

Но в выше опубликованном примере от 10 мая 2013, написанном Вами, никакой ручной установки типов параметров нет, и при этом пример замечательно работал тогда, я проверял сразу после Вашего ответа.

Закрыто