二进制(16)字段正在截断Guid的尾随零

问题描述 投票:3回答:2

在C#中,我有一个名为UniqueId的byte[]字段。我将此字段存储为SQL Server数据库(EF6)中的二进制(16)。

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

System.ArgumentException:GUID的字节数组必须长度为16个字节。

在调查之后,我注意到每当我生成的guid在十六进制末尾包含“00”时,SQL会截断它!

例:

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

SQL Server中存储的二进制文件(16):0xFF96F954777E8941A04774CD157C5C(15字节)

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

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

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

exec sp_executesql N'INSERT [dbo].[customers]([UniqueId])
VALUES (@0)',N'@0 varbinary(max)',@0=0xFF96F954777E8941A04774CD157C5C00
c# sql sql-server entity-framework guid
2个回答
6
投票

如果列的BINARY(16)设置为ANSI_PADDING且列允许OFFNULL),则会在demo中看到此行为。

修复它理想情况下将涉及更改表定义,以便列使用uniqueidentifier数据类型或至少具有ANSI_PADDING

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


0
投票

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

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);
© www.soinside.com 2019 - 2024. All rights reserved.