Проблема сериализации при использовании метода WriteXML - PullRequest
0 голосов
/ 14 ноября 2011

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

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

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

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 08 апреля 2015

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

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

Набор данных работает в двух режимах, хотя вы НЕ МОЖЕТЕ сказать об этом извне.

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

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

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

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

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

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

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

Некоторые эксперименты научили меня, что в этой ситуации меньше значит больше. Если DataSet читает схему и находит НЕТ отношений или ключевых столбцов, он будет работать в режиме «b», в противном случае он будет работать в режиме «a». МОЖЕТ быть возможным, что мы все еще можем получить набор данных режима 'b' с НЕКОТОРЫМИ отношениями или Key-Columns, но это не относилось к нашей проблеме.

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

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

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);
}

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

1 голос
/ 14 ноября 2011

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

...