1

我问了这个问题,这导致我做了以下事情。

  • 创建 C# 对象结构的 XML 表示,以便将其传递给 SQLServer。
  • 创建一个存储过程,对 XML 进行散列处理,然后将 XML 分解为相关表,并将散列存储在根表中以便快速查找。

这意味着我可以将复杂的对象数据传递给 SQLServer 并在哈希上进行查找,而不是尝试将 XML 与表进行分解和匹配(我也可以这样做,但速度很慢(呃))......

然而 - 关于 XML 的好处之一是您可以格式化它,例如缩进等 - 而且 - 属性顺序并不重要。但是,当您散列某些内容时,格式和缩进很重要。所以我在 C# 中所做的是......

  • 通过将所有属性按字母顺序排列来规范化 XML
  • 使用 .ToString(DisableFormatting) 删除额外的格式空间

这很好用,但是当我测试时,格式化XML 更容易,所以我可以更容易地看到我传递给存储过程的内容。

如果可以信任 SQLServer 来保留属性顺序,那就太好了,但它不能......

不保留 XML 实例中属性的顺序。当您查询存储在 xml 类型列中的 XML 实例时,生成的 XML 中的属性顺序可能与原始 XML 实例不同。

这意味着我不能使用 SQLServer 的 XML 数据类型来规范化数据。

困扰我的是,在某些时候有人会使用我的 proc 并认为“哦,太好了,XML,属性顺序无关紧要,格式无关紧要,表示的数据是相同的”但是,当我散列时,这不是不会是这样。

有人有解决这个问题的方法吗?我真的不想在 T-SQL 中编写 XML 解析器!!或者使用其他人编写的 XML 解析器来规范化它。为什么 SQLServer XML 数据类型不能只保留属性顺序?

我想我可以“信任”我的应用程序始终以相同的格式/顺序传递 XML,从而为同一对象产生相同的哈希值。但我对存储过程也必须“信任”应用程序才能做到这一点的想法感到不舒服。我希望能够以某种方式检查 XML 的规范化,它显然会更健壮。

4

1 回答 1

0

我将尝试序列化存储过程中的对象。

让我们假设以下类:

class MyCustomObject 
{
    int id;
    string SomeField;
}

然后,您可以使用存储过程,在其中序列化 xml 中的对象并计算输入参数的校验和,然后在另一个存储过程中,您可以传递 HashValue(checksum) 和 Xml。通过反序列化 Xml,你可以计算 Xml 中字段的校验和,并将其与传递的 HashValue 进行比较。

试试这个代码:(注意你应该存储哈希值并将其返回给调用者并对xml做一些事情)

CREATE PROCEDURE HashObject(@id int, @SomeField varchar(255)) AS
BEGIN
    SELECT
        CHECKSUM(@id, @SomeField) AS CalculatedHashValue,
        (SELECT @id AS ID, @SomeField AS SomeField FOR XML RAW('xmlRowName')) AS Xml_Data,
        @id AS SPCall_ID,
        @SomeField AS SPCall_SomeField
END
GO

CREATE PROCEDURE CheckHash(@HashValue INT, @data XML) AS
BEGIN
    SELECT  
        CHECKSUM(rt.value('@ID', 'int'), rt.value('@SomeField', 'varchar(255)')) AS Xml_CalculatedHashValue,
        @data Xml_Data,
        rt.value('@ID', 'int') AS Xml_ID,
        rt.value('@SomeField', 'varchar(255)') AS Xml_SomeField,
        @HashValue AS SPCall_HashValue

    FROM @data.nodes('xmlRowName') AS nd(rt)

END
GO

DECLARE @id INT = 11
DECLARE @SomeField varchar(255) = 'string value'
DECLARE @data XML

EXEC dbo.HashObject @id, @SomeField

SET @data = (SELECT @id AS ID, @SomeField AS SomeField FOR XML RAW('xmlRowName'))
EXEC dbo.CheckHash 0, @data

SET @data = (SELECT 25 AS ID, 'diferent string value' AS SomeField FOR XML RAW('xmlRowName'))
EXEC dbo.CheckHash 0, @data
GO  
于 2013-08-21T12:54:18.010 回答