Linq2SQL, хранящий XElement в базе данных SQL Server, удаляет пробелы - PullRequest
0 голосов
/ 25 сентября 2018

Могу ли я заставить System.Data.Linq.DataContext хранить XML в столбце XML таблицы SQL Server, сохраняя пробелы или есть какой-либо другой способ?

Мой тестовый код выглядит следующим образом:

        Guid MyNewQid = Guid.NewGuid();
        using (DataClassesDataContext context = DataClassesDataContext.CreateDataContext())
        {

            Guid myQID = Guid.Parse("{28da4eca-2c1a-4647-xxx-b398d1xxx013}");
            FromSwiftBck t2sData = context.GetTable<FromSwiftBck>().FirstOrDefault(o => o.QID == myQID);
            string messageLoaded = t2sData.CompleteMessage;
            int appHeaderLenght = messageLoaded.IndexOf("</AppHdr>") + 9;
            string strMsgHeader = messageLoaded.Substring(0, appHeaderLenght);
            string strMsgDocument = messageLoaded.Substring(appHeaderLenght);
            XElement serv = XElement.Parse(strMsgDocument, LoadOptions.PreserveWhitespace);

            SwiftOut swOut = new SwiftOut();
            swOut.QID = MyNewQid;
            swOut.InsertTime = DateTime.Now;
            swOut.Message = serv;
            swOut.Status = -100;
            swOut.Namespace = swOut.Message.GetDefaultNamespace().NamespaceName;
            swOut.MessageName = swOut.Message.Descendants().First().Name.LocalName;

            context.SwiftOuts.InsertOnSubmit(swOut);
            context.SubmitChanges();
        }
        using (DataClassesDataContext context = DataClassesDataContext.CreateDataContext())
        { 
            SwiftOut swOutStored = context.GetTable<SwiftOut>().FirstOrDefault(o => o.QID == MyNewQid);

            XElement storedXdoc = swOutStored.Message;

            MessageBox.Show(storedXdoc.ToString());

            context.SwiftOuts.DeleteOnSubmit(swOutStored);
            context.SubmitChanges();
        }
    }

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

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Короткая версия

Вам необходимо добавить атрибут xml:space.LoadOptions.PreserveWhitespace влияет только на синтаксический анализ строки.Это не добавляет атрибут.Вы должны добавить:

serv.SetAttributeValue(XNamespace.Xml + "space", "preserve");

Длинная версия

SQL Server поддерживает атрибут xml:space.Этот запрос:

create table #xmltest (field xml);

insert into #xmltest 
values
    ('<elem>         </elem>'),
    ('<elem xml:space="preserve">         </elem>');

select * from #xmltest;

Возвращает:

<elem />
<elem xml:space="preserve">         </elem>

Код вопроса, тем не менее, не определяет это. анализирует строку в XElement с PreserveWhitespace, но не добавляет этот атрибут.Если исходная строка не содержит этого атрибута, XElement также не будет его содержать.

Код вставляет эквивалент первого значения, которое не требует сохранения пробела.

Дляпример:

XElement.Parse("<elem>   </elem>",LoadOptions.PreserveWhitespace).ToString();

Создает <elem> </elem>, который не указывает, что пробел должен быть сохранен.PreserveWhitespace в этом случае переопределяет поведение по умолчанию, которое заключается в игнорировании пробела.

Без PreserveWhitespace Parse игнорирует пробелы и возвращает <elem></elem>.

С другой стороны:

XElement.Parse("<elem xml:space='preserve'>   </elem>").ToString()

Производит <elem xml:space="preserve"> </elem>.Нет необходимости использовать флаг PreserveWhitespace, сам XElement распознает и учитывает этот флаг.

Если исходная XML-строка содержит пробелы, но не содержит атрибут xml:space, онанеобходимо добавить, чтобы другие классы и приложения, такие как SQL Server, знали, что они должны сохранять пробелы.Следующий код:

var serv=XElement.Parse("<elem>   </elem>",LoadOptions.PreserveWhitespace);
serv.SetAttributeValue(XNamespace.Xml + "space", "preserve");
serv.ToString();

Вернет <elem xml:space="preserve"> </elem>, который будет распознан SQL Server.

Объединение всего этого вместе

Этот LINQв код SQL:

var serv=XElement.Parse("<elem>       </elem>",LoadOptions.PreserveWhitespace);
serv.SetAttributeValue(XNamespace.Xml + "space", "preserve");
Xmltests.InsertOnSubmit(new Xmltest{Field=serv});

Вставит:

<elem xml:space="preserve">       </elem>

В базу данных

0 голосов
/ 25 сентября 2018

Тип данных XML НЕ сохраняет ваше точное текстовое представление XML - он анализирует и токенизирует XML для более оптимального хранения.

SQL Server не гарантировать, что возвращаемый XML-файл точно такой же (с точки зрения форматирования, пробелов и т. д.), что и входные данные.

Насколько мне известно, не существует опций или настроек конфигурации для изменения этого поведения.

Подробнее см. Здесь:

https://docs.microsoft.com/en-us/sql/relational-databases/xml/xml-data-type-and-columns-sql-server?view=sql-server-2017

Собственное хранилище как тип данных xml

Данные хранятся во внутреннем представлении, которое сохраняет XML-содержимое данных...... Содержимое InfoSet не может быть идентичной копией текста XML, поскольку следующая информация не сохраняется : незначительные пробелы, порядок атрибутов, префиксы пространств имен,и XML декларация.

(акцент был добавлен мной)

...