如何将Guid正确插入SQLite的UNIQUEIDENTIFIER列避免值变更
这个问题的核心是SQLite与.NET Guid的字节序差异,加上你直接用原生SQL插入时绕过了NHibernate的类型转换逻辑导致的:
SQLite本身没有原生的UNIQUEIDENTIFIER类型,NHibernate在处理Guid映射时,会自动转换.NET Guid和SQLite存储字节之间的字节序差异。.NET的Guid结构中,前三个字段(Data1、Data2、Data3)采用小端字节序存储,而当你直接用x'...'格式的十六进制字符串插入时,是按字节顺序直接写入数据库,没有经过NHibernate的转换处理,导致存储的字节序和.NET Guid的预期不匹配,最终查询出来的Guid值就变了。
比如你插入的十六进制x'7A2AC599D32D03458608E5C614301387',对应的字节序列是7A 2A C5 99 D3 2D 03 45 86 08 E5 C6 14 30 13 87,但.NET Guid读取时会把前4字节、接下来2字节、再接下来2字节反转(因为小端序),所以就变成了99c52a7a-2dd3-4503-8608-e5c614301387。
方法1:使用参数化查询(推荐)
让NHibernate来处理Guid的类型转换,彻底避免手动处理字节序的麻烦。把Guid作为参数传入,而不是硬编码十六进制字符串:
// 定义你想要插入的目标Guid var desiredGuid = new Guid("7A2AC599-D32D-0345-8608-E5C614301387"); // 编写带参数的SQL语句 var sql = @"INSERT INTO Patient (Id, RemoteId, FirstName, LastName, ChartNumber, LastScanDate, RowStatus, SearchName, DateUpdated, IsAllPropertiesSynced) SELECT :patientId, 3072799, 'iRecord', 'Demo', '', '2017-06-04 07:53', 1, 'iRecordDemoiRecord', '2017-07-23 06:34', 1 WHERE NOT EXISTS(SELECT Id FROM Patient WHERE Id = :patientId);"; // 执行参数化查询 session.CreateSQLQuery(sql) .SetParameter("patientId", desiredGuid) .ExecuteUpdate();
这种方式下,NHibernate会自动根据SQLite的存储规则转换Guid的字节序,插入后查询得到的Guid就是你预期的值。
方法2:手动调整字节序(不推荐,易出错)
如果必须使用原生十六进制字符串插入,需要将.NET Guid的字节序转换成SQLite存储的格式。具体来说,你需要把目标Guid转换成.NET内部存储的字节序列,再转成十六进制字符串:
var desiredGuid = new Guid("7A2AC599-D32D-0345-8608-E5C614301387"); byte[] guidBytes = desiredGuid.ToByteArray(); // 转换成十六进制字符串(去掉分隔符) string hexString = BitConverter.ToString(guidBytes).Replace("-", ""); // 此时hexString的值是 "99C52A7AD32D03458608E5C614301387"
然后把这个十六进制字符串用x'...'包裹插入到SQL中:
INSERT INTO Patient (Id, RemoteId, FirstName, LastName, ChartNumber, LastScanDate, RowStatus, SearchName, DateUpdated, IsAllPropertiesSynced) SELECT x'99C52A7AD32D03458608E5C614301387', 3072799, 'iRecord', 'Demo', '', '2017-06-04 07:53', 1, 'iRecordDemoiRecord', '2017-07-23 06:34', 1 WHERE NOT EXISTS(SELECT Id FROM Patient WHERE Id = x'99C52A7AD32D03458608E5C614301387');
不过这种方法需要手动处理字节序,容易出错,所以更推荐用参数化查询的方式。
内容的提问来源于stack exchange,提问作者user3132295

