【问题标题】:Serialization Issue when using WriteXML method使用 WriteXML 方法时的序列化问题
【发布时间】:2011-12-28 20:03:27
【问题描述】:

我正在尝试对代码执行的操作是将数据集导出到 XML。

这是我目前正在使用的:

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

我的数据集是一个正确形成的类型化数据集(我的意思是,所有表都有 PK,并且在数据集中的所有现有表之间设置了 FK 关系)。一些关系是嵌套关系。表“TABLE”有两个 FK,同时是其他 8 个表的父级。

我收到以下错误:“无法继续序列化 DataTable 'TABLE'。它包含一个 DataRow,它在同一个外键上有多个父行。

有人给我一些关于我做错了什么的指点吗?以及为什么我会收到此错误消息?

提前致谢。

【问题讨论】:

    标签: c# xml-serialization dataset


    【解决方案1】:

    我知道这有点晚了,但我找到了解决方法。

    我在尝试将架构读入具有关系的数据集时遇到了同样的问题。在这种情况下,您将得到的错误是: '同一个表'{0}'不能是两个嵌套关系中的子表' 我将分享我所学到的

    数据集以两种模式运行,但您无法从外部分辨出来。

    1. (a) 我是严格/手动创建的数据集,不喜欢嵌套关系
    2. (b) 我是一个序列化对象的容器,一切正常。

    您创建的数据集当前为“a”,我们希望将其设为“b”。 在“加载”数据集 (xml) 或其他一些考虑因素时决定它以哪种模式运行。

    我花了很多时间阅读 DataSet 的代码以找出一种欺骗它的方法,我发现 MS 可以通过在数据集上添加一个属性和一些额外的检查来解决这个问题。查看 DataRelation 的源代码:http://referencesource.microsoft.com/#System.Data/System/Data/DataRelation.cs,d2d504fafd36cd26,references,我们需要欺骗的唯一方法是 'ValidateMultipleNestedRelations' 方法。)

    诀窍是欺骗数据集,使其认为它自己建立了所有关系。我发现这样做的唯一方法是通过使用序列化实际让数据集创建它们。

    (我们在系统的一部分中使用此解决方案,我们正在使用面向 DataSet 的第 3 方产品创建输出。)

    在meta中,你要做的是:

    1. 在代码中创建数据集,包括关系。如果你试试 可以模仿 MS 命名约定(虽然不确定是否需要)
    2. 序列化您的数据集(最好不要在其中包含任何行)
    3. 使序列化数据集看起来像 MS 序列化它。 (生病 在下面展开)
    4. 将修改后的数据集读入新实例。
    5. 现在您可以导入您的行,MS 不检查关系, 事情应该会奏效。

    一些实验告诉我,在这种情况下,少即是多。 如果一个 DataSet 读取一个模式,并且发现没有关系或键列,它将在模式“b”下运行,否则它将在模式“a”下运行。 有可能我们仍然可以获得具有某些关系或键列的“b”模式数据集,但这与我们的问题无关。

    所以,我们开始吧,这段代码假设您有一个知道如何处理数据集的扩展方法“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);
    }
    

    注意,正如我在开始时所说的,当我们加载数据集时,我必须解决这个问题,虽然您正在保存数据集,但解决方法将是相同的。

    【讨论】:

      【解决方案2】:

      两个外键导致问题。钥匙的另一端被认为是父母,所以你有两个。在编写 XML 时,一个元素只能有一个父元素(除非该元素出现两次,在每个父元素下出现一次)。可能的解决方案包括删除一个外键(我很欣赏这可能会以其他方式破坏您的应用程序),或者,根据您的dataSet 的初始化方式,尝试将EnforceConstraints 设置为false

      【讨论】:

      • 所以,据我了解,如果你想序列化一个 XML,你不能让两个父表指向一个子表,同时让该子表作为父表与其他表相关.将 EnforceConstraints 设置为 false 不起作用,但值得一试。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-05
      • 1970-01-01
      • 1970-01-01
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多