Обработка значений из @DiffXml
@DiffXml
используется для получения данных из полей, в которые были внесены изменения в результате:
Подробнее о работе с данными типа XML в MS SQL можно почитать в документации Microsoft.
Добавление новой записи
<Record>
<Title>Преступление и наказание</Title>
<Author>Федор Достоевский</Author>
<Price>485</Price>
<Order_o2m>
<Record>
<DateRegistration>06/01/2023 15:32:12</DateRegistration>
<Quantity>500</Quantity>
<Comment>Регулярный заказ</Comment>
</Record>
<Record>
<DateRegistration>06/08/2023 15:32:37</DateRegistration>
<Quantity>500</Quantity>
<Comment>Промо акция</Comment>
</Record>
</Order_o2m>
</Record>
Вся запись всегда хранится в теге
Record
.Каждый тег, вложенный в
Record
, соответствует полю объекта, в котором изменяются записи.В теге логического поля вложено столько тегов
Record
, сколько записей было изменено в объекте, на который это поле ссылается (<Order_o2m>
— логическое o2m-поле).
Удаление записи
<Record destroy="true">
<ID>3</ID>
</Record>
Для удаляемых записей в
Record
указан атрибутdestroy="true"
.В
DiffXml
попадает толькоID
удаляемой записи.
Если при удалении записи необходимо получить доступ к значению какого-либо атрибута, в процедуре-обработчике следует воспользоваться select
-ом к таблице, из которой удаляется запись.
Изменение существующей записи
<Record>
<ID>2</ID>
<Price />
<Author>Федор Михайлович Достоевский</Author>
<Order_o2m>
<Record>
<ID_Book>2</ID_Book>
<DateRegistration>04/19/2023 15:39:55</DateRegistration>
<Quantity>150</Quantity>
</Record>
</Order_o2m>
</Record>
В
@DiffXml
попадают только:ID
изменяемой записи.Поля, данные в которых были изменены (в данном примере
Title
не был изменен ).
При попытке получить значение из тега, которого нет в
@DiffXml
с помощью методаxml.value()
вернетсяnull
.- В примере:
@DiffXml.value('(/Record/Title)', 'varchar(255)')
вернетnull
.
- В примере:
<Price />
означает, что значение в этом поле было изменено наnull
.При получении значения с помощью метода
xml.value()
из тега, значение в котором было изменено наnull
, вернется значение по умолчанию для данного типа данных.В примере:
@DiffXml.value('(/Record/Price)', 'int')
вернет0
.Значения по умолчанию для используемых типов данных:
Маска
Число
datetime
1900-01-01 00:00:00.000
date
1900-01-01
time
00:00:00
bit
0
int
0
decimal(18, 2)
0.00
varchar(n)
Пустая строка: (' ')
Изменение записей в объекте, на который ссылается логическое поле
При изменении существующей записи, в тег
Record
записываетсяID
этой записи и теги всех полей, в которых произошли изменения.При удалении записи, у тега
Record
появляется атрибутdestroy
со значениемtrue
.Для удаляемой записи в теге
Record
записаны теги всех полей объекта с соответствующими значениями (включая системные поля MDT).Для новой записи в теге
Record
отсутствуетID
, т.к. он еще не присвоен.
Парсинг @DiffXml
Используется для обработки одновременного изменения нескольких записей в объекте, на который ссылается логического поле. Результат данного запроса можно, например, записать во временную таблицу для дальнейшего использования в рамках процедуры.
select
d.n.value('(ID)[1]', 'int') as ID_Book
/*
Добавляем флаги, с помощью которых можно будет фильтровать записи по категориям:
"новые записи" - FlagNew = 1, FlagDeleted = 0,
"измененные записи" - FlagNew = 0, FlagDeleted = 0,
"удаленные записи" - FlagNew = 0, FlagDeleted = 1
*/
,iif(epm.ID is not null, 0, 1) as FlagNew
,iif(d.n.value('(@destroy)[1]', 'varchar(255)') is null, 0, 1) as FlagDeleted
-- Получаем данные по каждому интересующему полю
,case isnull(d.n.value('(DateRegistration)[1]', 'date'), o.DateRegistration)
-- Если первый аргумент возвращает значение по умолчанию, обрабатываем как "null"
when cast('1900-01-01' as date)
then null
-- В противном случае выбираем первое значение отличное от "null"
else isnull(d.n.value('(DateRegistration)[1]', 'date'), o.DateRegistration)
end as DateRegistration
,case isnull(d.n.value('(Quantity)[1]', 'int'), o.Quantity)
when 0
then null
else isnull(d.n.value('(Quantity)[1]', 'int'), o.Quantity)
end as Quantity
,case isnull(d.n.value('(Comment)[1]', 'varchar(8000)'), o.Comment)
when ''
then null
else isnull(d.n.value('(Comment)[1]', 'varchar(8000)'), o.Comment)
end as Comment
-- Получаем набор строк, соответствующих каждому Record-у, вложенному в логическое поле
from @DiffXml.nodes('/Record/Order_o2m/Record') as d(n)
-- Объединяем для получения данных о тех полях существующих записей, которые не были изменены
left join onboarding.[Order] as o on o.ID = d.n.value('(ID)[1]', 'int')
Отлов @DiffXml
в БД
Чтобы отловить @DiffXml
в БД, нужно:
Создать таблицу (например
dbo.DiffXml
) с полем типа XML.drop table if exists dbo.DiffXml go create table dbo.DiffXml ( ID int null ,DiffXml xml null )Перезагрузить объекты в MDT, т.к. появилась новая таблица.
В SQL обработчике написать инструкцию на заполнение таблицы значением из переменной
@DiffXml
.create or alter procedure rds.usp_AfterSavePassForBrigadier @ID int ,@DiffXml xml as set xact_abort on set nocount on begin try insert into dbo.DiffXml (ID, DiffXml) select @ID ,@DiffXml end try begin catch ;throw end catchЗайти в MDT и сохранить запись, предварительно изменив в ней значения.
Просмотреть, какой XML приходит с помощью
select
из таблицы.select * from dbo.DiffXml