Binary(16) 字段正在截断 Guid 的尾随零

Binary(16) field Is truncating Guid's trailing zeros

在 C# 中,我有一个名为 UniqueId 的 byte[] 字段。我将此字段作为 Binary(16) 存储在 SQL 服务器数据库 (EF6) 中。

我注意到有时存储的 guid 是 15 字节而不是 16 字节。当我从数据库中检索值后执行 var guid = new Guid(uniqueId) 时,这会导致以下异常:

System.ArgumentException : Byte array for GUID must be exactly 16 bytes long.

对此进行调查后,我注意到只要我生成的 guid 在十六进制末尾包含“00”,SQL 就会截断它!

示例:

生成的 Guid(通过 Guid.NewGuid): FF96F954777E8941A04774CD157C5C00(16 字节)

存储在SQL服务器中的二进制文件(16):0xFF96F954777E8941A04774CD157C5C(15字节)

如果您注意到,最后的 00 被截断了。因此,如果我查询该字段并尝试将其字节转换为 Guid,我将得到 System.ArgumentException.

还有其他人遇到这个问题吗?解决方法是什么?我正在考虑 Guid 的包装器,它一直生成 guid 直到它没有尾随零,但这看起来很老套。

更新 1:由于你们要求,我 运行 SQL 分析器,这是由 EF(删节版)生成的 SQL:

exec sp_executesql N'INSERT [dbo].[customers]([UniqueId])
VALUES (@0)',N'@0 varbinary(max)',@0=0xFF96F954777E8941A04774CD157C5C00

如果列的 ANSI_PADDING 设置为 OFF 且列允许 NULL (demo),则 BINARY(16) 会出现此行为。

理想情况下,修复它会涉及更改 table 定义,以便该列使用 uniqueidentifier 数据类型或至少启用 ANSI_PADDING

要更改 ANSI_PADDING 语义将涉及 SET ANSI_PADDING ON 然后添加一个新的 binary(16) 列 - 从旧列填充它,然后删除并重命名。这是如果您的应用程序可以容忍可能的列重新排序,如果它无法处理这种重新排序并且 UniqueId 不是 table 中的最后一列,您将需要创建一个新的 table 并迁移所有数据。

如果您不想更改数据库设置,您可以随时填充从数据库返回的内容,例如

byte[] uniqueId = new byte[15]; //however this comes back from the db;
byte[] uniqueIdPadded = new byte[16];
uniqueId.CopyTo(uniqueIdPadded, 0);
var guid = new Guid(uniqueIdPadded);