Проблема с сериализацией при использовании метода WriteXml

#c# #xml-serialization #dataset

#c# #xml-сериализация #набор данных

Вопрос:

Что я пытаюсь сделать с кодом, так это экспортировать набор данных в XML.

Это то, что я сейчас использую:

 dataSet.WriteXml(fileDialog.FileName, XmlWriteMode.WriteSchema);
  

Мой набор данных представляет собой правильно сформированный типизированный набор данных (под этим я подразумеваю, что все таблицы имеют PK, и отношения FK установлены между всеми существующими таблицами в наборе данных). Некоторые отношения являются вложенными отношениями. Таблица «TABLE» имеет два FK и в то же время является родительской для других 8 таблиц.

Я получаю следующую ошибку: «Не удается продолжить сериализацию DataTable ‘TABLE’. Он содержит поток данных, который имеет несколько родительских строк с одним и тем же внешним ключом.«

Может быть, кто-нибудь подскажет мне, что я делаю неправильно? и почему я получаю это сообщение об ошибке?

Заранее спасибо.

Ответ №1:

Я знаю, что немного поздно, но я нашел обходной путь.

Я столкнулся с той же проблемой при попытке прочитать схему в наборе данных, который имеет отношения. Ошибка, которую вы получите в этом случае, такова: ‘Одна и та же таблица'{0}’ не может быть дочерней таблицей в двух вложенных отношениях’ Я поделюсь тем, что я узнал

Набор данных работает в двух режимах, хотя снаружи этого не скажешь.

  1. (a) Я использую строгий / созданный вручную набор данных, мне не нравятся вложенные отношения
  2. (b) Я являюсь контейнером для сериализованного объекта, все идет своим чередом.

Созданный вами набор данных в настоящее время является ‘a’, мы хотим сделать его ‘b’. В каком режиме он работает, определяется при «загрузке» набора данных (xml) и / или по некоторым другим соображениям.

Я трачу лихорадочные часы на чтение кода DataSet, чтобы найти способ обмануть его, и я обнаружил, что MS может решить проблему, просто добавив свойство в dataset и проведя несколько дополнительных проверок. Проверьте исходный код для ссылки на данные: http://referencesource.microsoft.com/#System.Data/System/Data/DataRelation.cs,d2d504fafd36cd26,references и что единственный метод, который нам нужно обмануть, — это метод ‘ValidateMultipleNestedRelations’.)

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

(Мы используем это решение в той части нашей системы, где мы создаем выходные данные с помощью продукта стороннего производителя, ориентированного на набор данных.)

В meta то, что вы хотите сделать, это:

  1. Создайте свой набор данных в коде, включая взаимосвязи. Попробуйте, можете ли вы имитировать соглашение об именовании MS (хотя не уверены, требуется ли)
  2. Сериализуйте свой набор данных (лучше всего, чтобы в нем не было строк)
  3. Сделайте сериализованный набор данных таким, как его сериализовала MS. (Я подробнее остановлюсь на этом ниже)
  4. Прочитайте измененный набор данных в новый экземпляр.
  5. Теперь вы можете импортировать свои строки, MS не проверяет взаимосвязи, и все должно работать.

Некоторые эксперименты научили меня, что в этой ситуации меньше значит больше. Если набор данных считывает схему и не находит связей или ключевых столбцов, он будет работать в режиме ‘b’, в противном случае он будет работать в режиме ‘a’. Возможно, мы все еще сможем получить набор данных в режиме ‘b’ с НЕКОТОРЫМИ связями или ключевыми столбцами, но это не имеет отношения к нашей проблеме.

Итак, поехали, в этом коде предполагается, что у вас есть метод расширения ‘Serialize’, который знает, как обрабатывать набор данных.

Предположим, что sourceDataSet — это набор данных, содержащий только схему. Целью будет фактически используемый набор данных:

 var sourceDataSet = new DataSet();
var source = sourceDataSet.Serialize();
// todo: create the structure of your dataset.
var endTagKeyColumn = " msdata:AutoIncrement="true" type="xs:int" msdata:AllowDBNull="false" use="prohibited" /";
var endTagKeyColumnLength = endTagKeyColumn.Length - 1;

var startTagConstraint = "<xs:unique ";
var endTagConstraint = "</xs:unique>";
var endTagConstraintLength = endTagConstraint.Length - 1;

var cleanedUp = new StringBuilder();
var subStringStart = 0;
var subStringEnd = source.IndexOf(endTagKeyColumn);

while (subStringEnd > 0)
{
    // throw away unused key columns.
    while (source[subStringEnd] != '<') subStringEnd--;
    if (subStringEnd - subStringStart > 5)
    {
        cleanedUp.Append(source.Substring(subStringStart, subStringEnd - subStringStart));
    }
    subStringStart = source.IndexOf('>', subStringEnd   endTagKeyColumnLength)   1;
    subStringEnd = source.IndexOf(endTagKeyColumn, subStringStart);
}

subStringEnd = source.IndexOf(startTagConstraint, subStringStart);
while (subStringEnd > 0)
{
    // throw away relationships.
    if (subStringEnd - subStringStart > 5)
    {
        cleanedUp.Append(source.Substring(subStringStart, subStringEnd - subStringStart));
    }
    subStringStart = source.IndexOf(endTagConstraint, subStringEnd)   endTagConstraintLength;
    subStringEnd = source.IndexOf(startTagConstraint, subStringStart);
}
cleanedUp.Append(source.Substring(subStringStart   1));
target = new DataSet();
using (var reader = new StringReader(cleanedUp.ToString()))
{
    target.EnforceConstraints = false;
    target.ReadXml(reader, XmlReadMode.Auto);
}
  

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

Ответ №2:

Причиной проблемы являются два внешних ключа. Другой конец ключей считается родительским, поэтому у вас их два. При написании XML элемент может иметь только одного родителя (если только элемент не появляется дважды, по одному разу под каждым родителем). Возможные решения включают удаление одного из внешних ключей (который, я понимаю, может привести к поломке вашего приложения другими способами) или, в зависимости от того, как ваш dataSet инициализирован, попробуйте установить EnforceConstraints на false .

Комментарии:

1. Итак, как я понял, если вы хотите сериализовать XML, у вас не может быть двух родительских таблиц, указывающих на дочернюю таблицу, и в то же время эта дочерняя таблица связана с другими как родительская itslef . Установка EnforceConstraints в false не сработала, но попробовать стоило.