在C#中,我有一个byte[]
字段,称为UniqueId。我将此字段作为Binary(16)存储在SQL Server数据库(EF6)中。
我注意到有时存储的guid是15字节而不是16字节。当我从数据库中检索值后执行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,直到没有尾随零为止,但这似乎很hack。
更新1:由于你们的要求,我运行了SQL事件探查器,这是EF(节略版)生成的SQL:
exec sp_executesql N'INSERT [dbo].[customers]([UniqueId])
VALUES (@0)',N'@0 varbinary(max)',@0=0xFF96F954777E8941A04774CD157C5C00
答案 0 :(得分:6)
如果该列的BINARY(16)
设置为ANSI_PADDING
并且该列允许使用OFF
(demo),则您会看到NULL
的这种行为。
修复该问题最好是更改表定义,以便该列使用uniqueidentifier
数据类型或至少打开ANSI_PADDING
。
要更改ANSI_PADDING
的语义,将涉及SET ANSI_PADDING ON
,然后添加一个新的binary(16)
列-从旧列中填充它,然后拖放并重命名。这是您的应用程序可以忍受列的可能重新排序,如果它不能应对这种重新排序并且UniqueId
不是表中的最后一列,则需要创建一个新表并在所有表之间迁移所有数据
答案 1 :(得分: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);