Ошибка Multiple-step OLE DB operation generates error...

Обсуждение возникших проблем, предложений и ошибок SDAC компонентов
Ответить
Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Ошибка Multiple-step OLE DB operation generates error...

Сообщение Rajoe » Пн 24 сен 2012 15:49

Здравствуйте.
Использую Delphi 7 и SDAC 6.1.3.
Есть представление, собранное из двух таблиц и имеющее триггеры INSTEAD OF INSERT, UPDATE и DELETE. Таблицы связаны 1 к 1 по автоинкрементному полю. При работе с этим представлением через TMSQuery возникло две проблемы:
1. Компонент TMSQuery не получал новое значение ключа при добавлении записи, так как scope_identity() возвращала в этом случае пустое значение.
2. При удалении записи получаю сообщение о неверном типе автоматически сгенерированного компонентом параметра, через который передаётся значение ключа удаляемой записи.

Первую проблему удалось решить, передав новое значение ключа из триггера через контекст. При этом пришлось явно указать запрос на вставку записи в свойстве SQLInsert, заменив select :id = scope_identity() на select :id = cast(context_info() as int). Работает нормально, но очень жаль отказываться от автоматической генерации запроса на вставку. Хотелось бы иметь возможность скорректировать такой запрос непосредственно перед его выполнением. Или такая возможность существует? Тогда подскажите, пожалуйста, как это можно сделать.

Во втором случае также выполняется автоматически сгенерированный запрос на удаление записи, который в dbMonitor'е выглядит так:

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

DELETE FROM vwTask
WHERE
  idMain = ?;
Выполнение этого запроса приводит к ошибке:

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

Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.

Parameter[1] :P_0_Old_idMain - invalid ParamType (Status = 1h).
Список параметров в dbMonitor'е почему-то содержит два одинаковых:

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

Name            Type          Data Type      In Value     Out Value
P_0_Old_idMain  IN            AutoInc        123870
P_0_Old_idMain  IN            AutoInc        123870
Прописывание SQLDelete выражением

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

delete from vwTask where idMain = :idMain
приводит к возникновению той же ошибки, только со ссылкой на параметр из ручного запроса:

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

Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.

Parameter[1] :P_0_idMain - invalid ParamType (Status = 1h).
При этом список параметров снова содержит два параметра, но теперь уже разных:

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

Name            Type          Data Type      In Value     Out Value
P_0_Old_idMain  IN            AutoInc        123870
P_0_idMain      IN            AutoInc        123870
Что можно сделать в этом случае?

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

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение AndreyZ » Вт 25 сен 2012 11:04

Здравствуйте,

Для того чтобы дать Вам детальный и корректный ответ, мне нужна дополнительная информация. Приведите пожалуйста скрипт для создания Вашего представления, таблиц которые учавствуют в этом представлении и триггеров. Также приведите версию SQL Server который Вы используете и версию провайдера (OLEDB или SQL Native Client). Вы можете найти их на закладке Info редактора компонента TMSConnection.

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Rajoe » Вт 25 сен 2012 14:53

Microsoft SQL Server: 09.00.4053
Microsoft OLE DB Provider for SQL Server: 08.00.1132

Представление:

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

CREATE VIEW [dbo].[vwTask] with view_metadata as
	select m.*, t.idCFU_1, t.idCFU_2, t.nCFUprc_1, t.nCFUprc_2, t.nControl, t.idTaskCategory
		from rtMain m
			inner join rtTask t on t.idMain = m.idMain
Триггеры:

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

CREATE TRIGGER [dbo].[TID_vwTask]
   ON [dbo].[vwTask]
   INSTEAD OF DELETE
AS 
BEGIN
	SET NOCOUNT ON;
	delete from rtMain where idMain in (select idMain from deleted);
	if @@error <> 0
	begin
		raiserror('Ошибка удаления задачи из списка.', 16, 1);
		rollback;
		return;
	end;
	
	return;
END

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

CREATE TRIGGER [dbo].[TII_vwTask]
   ON [dbo].[vwTask]
   INSTEAD OF INSERT
AS 
BEGIN
	SET NOCOUNT ON;
	
	if (select count(*) from inserted) > 1
	begin
		raiserror('Нельзя добавлять больше одной задачи за раз', 16, 1);
		rollback;
		return;
	end;
	
	declare @IDs table (id int);
	insert into rtMain (
			sName, idPerson, idRequester, idParent, idCFU, idDepartment, nPrior, nType, dPlan, dFloat, dFact, dBegin, sNotes, sOrderNumb,
			dOrderDate, idBudget, idBoss, sComment, sIncOrderNumb, dIncOrderDate, bNotice, nPlan, sPatchSvn)
		output inserted.idMain into @IDs
		select	sName, idPerson, idRequester, idParent, idCFU, idDepartment, nPrior, 2, dPlan, dFloat, dFact, dBegin, sNotes, sOrderNumb,
				dOrderDate, idBudget, idBoss, sComment, sIncOrderNumb, dIncOrderDate, bNotice, nPlan, sPatchSvn
			from inserted;
	if @@error <> 0
	begin
		raiserror('Задача не добавлена в таблицу rtMain', 16, 1);
		rollback;
		return;
	end;
	
	declare @id int;
	select @id = id from @IDs;
	exec coreIntToContext @iValue = @id;
	
	insert into rtTask (idMain, nControl, idCFU_1, idCFU_2, nCFUprc_1, nCFUprc_2, idTaskCategory)
		select @id, nControl, idCFU_1, idCFU_2, nCFUprc_1, nCFUprc_2, idTaskCategory from inserted;
	if @@error <> 0
	begin
		raiserror('Задача не добавлена в таблицу rtTask', 16, 1);
		rollback;
		return;
	end;
	
	declare @idState int;
	select @idState = idState from infState where sName = 'Не начата';
	insert into repMain (
			idMain, idState, dState, sState, dBeginRep, dEndRep, sCreateUser, dCreateDate, nDays)
		values (
			@id, @idState, cast(floor(cast(getdate() as float)) as datetime), 'Отчет о создании.', '19000909', '19000909', suser_sname(), getdate(), 0)
	if @@error <> 0
	begin
		raiserror('Не добавлен отчёт о создании задачи', 16, 1);
		rollback;
		return;
	end;
	
	return;
END

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

CREATE TRIGGER [dbo].[TIU_vwTask]
   ON [dbo].[vwTask]
   INSTEAD OF UPDATE
AS 
BEGIN
	SET NOCOUNT ON;
	update rtMain
		set	sName = I.sName, idPerson = I.idPerson, idRequester = I.idRequester, idParent = I.idParent, idCFU = I.idCFU,
			idDepartment = I.idDepartment, nPrior = I.nPrior, dPlan = I.dPlan, dFloat = I.dFloat, dFact = I.dFact, dBegin = I.dBegin,
			sNotes = I.sNotes, sOrderNumb = I.sOrderNumb, dOrderDate = I.dOrderDate, idBudget = I.idBudget, idBoss = I.idBoss,
			sComment = I.sComment, sIncOrderNumb = I.sIncOrderNumb, dIncOrderDate = I.dIncOrderDate, bNotice = I.bNotice,
			nPlan = I.nPlan, sPatchSvn = I.sPatchSvn
		from inserted I
		where I.idMain = rtMain.idMain;
	if @@error != 0
	begin
		raiserror('Ошибка при сохранении данных задачи в таблице rtMain.', 16, 1);
		rollback;
		return;
	end;
	
	update rtTask
		set nControl = I.nControl, idCFU_1 = I.idCFU_1, idCFU_2 = I.idCFU_2, nCFUprc_1 = I.nCFUprc_1, nCFUprc_2 = I.nCFUprc_2,
			idTaskCategory = I.idTaskCategory
		from inserted I
		where I.idMain = rtTask.idMain;
	if @@error != 0
	begin
		raiserror('Ошибка при сохранении данных задачи в таблице rtTask.', 16, 1);
		rollback;
		return;
	end;
	
	return;
END
Таблицы:

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

CREATE TABLE [dbo].[rtMain](
	[idMain] [int] IDENTITY(1,1) NOT NULL,
	[sName] [varchar](255) NULL,
	[idPerson] [int] NULL,
	[idRequester] [int] NULL,
	[idParent] [int] NULL,
	[idCFU] [int] NULL,
	[idDepartment] [int] NULL,
	[nPrior] [int] NULL,
	[nType] [smallint] NULL,
	[dPlan] [datetime] NULL,
	[dFloat] [datetime] NULL,
	[dFact] [datetime] NULL,
	[dBegin] [datetime] NULL,
	[sNotes] [varchar](5000) NULL,
	[sOrderNumb] [varchar](800) NULL,
	[dOrderDate] [datetime] NULL,
	[idOld] [int] NULL,
	[idBudget] [int] NULL,
	[dCreateDate] [datetime] NOT NULL DEFAULT (getdate()),
	[sCreateLogin] [varchar](50) NOT NULL DEFAULT (suser_sname()),
	[idBoss] [int] NULL,
	[sComment] [varchar](5000) NULL,
	[sIncOrderNumb] [varchar](800) NULL,
	[dIncOrderDate] [datetime] NULL,
	[dEditDate] [datetime] NOT NULL DEFAULT (getdate()),
	[sEditLogin] [varchar](35) NOT NULL DEFAULT (suser_sname()),
	[bNotice] [tinyint] NULL,
	[nPlan] [tinyint] NULL,
	[sPatchSvn] [varchar](255) NULL,
	[xRecTime] [timestamp] NULL,
 CONSTRAINT [PK_rtMain] PRIMARY KEY CLUSTERED 
(
	[idMain] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]

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

CREATE TABLE [dbo].[rtTask](
	[idMain] [int] NOT NULL,
	[idCFU_1] [int] NULL,
	[idCFU_2] [int] NULL,
	[nCFUprc_1] [int] NULL,
	[nCFUprc_2] [int] NULL,
	[nControl] [tinyint] NOT NULL CONSTRAINT [DF_rtTask_nControl]  DEFAULT (0),
	[idTaskCategory] [int] NULL,
	[sLink] [varchar](255) NULL,
	[sID] [varchar](255) NULL,
	[idMask] [int] NULL,
 CONSTRAINT [PK_rtTask] PRIMARY KEY CLUSTERED 
(
	[idMain] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Rajoe » Пт 28 сен 2012 09:59

Как мой вопрос, есть какие-то результаты?

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

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Alexp » Пт 28 сен 2012 10:26

Добрый день,

Пожалуйста пришлите также скрипт на создание процедуры coreIntToContext используемой в триггере TII_vwTask

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

...
exec coreIntToContext @iValue = @id;  
...

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Rajoe » Пт 28 сен 2012 11:51

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

CREATE PROCEDURE [dbo].[coreIntToContext]
	@iValue int
AS
BEGIN
	declare @context varbinary(128);
	set @context = cast(@iValue as binary(128));
	set context_info @context;
END
GO

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Rajoe » Вт 02 окт 2012 09:12

Здравствуйте.

Есть ли какие-то новости по моему вопросу?

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

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Alexp » Вт 02 окт 2012 11:36

Добрый день,

К сожалению возможности изменить сгенерированный запрос "налету" нету, поэтому вам необходимо задавать свой INSERT запрос при работе с такими VIEW.
Мы не смогли воспроизвести ошибку при удалении данных из VIEW, попробуйте скачать последнюю версию SDAC 6.5.9 и воспроизвести проблему с удалением на ней

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Rajoe » Ср 03 окт 2012 13:38

Спасибо. Ещё один вопрос вдогонку: почему в описанном случае у меня не работает встроенный SQL-генератор?

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

Re: Ошибка Multiple-step OLE DB operation generates error...

Сообщение Alexp » Чт 04 окт 2012 10:57

Добрый день,

Встроеный генератор для приведенного примера генерирует оба запроса (INSERT и DELETE), однако всвязи со спецификой работы SQL Server метод scope_identity() действительно возвращает пустое значение при использовании тако VIEW. Мы рассмотрим возможность изменить генерируемы запрос
для таких ситуаций в одной из следующих версий продукта

Ответить