带有 GUID 全零的 MS SQL 表

Posted

技术标签:

【中文标题】带有 GUID 全零的 MS SQL 表【英文标题】:MS SQL table with GUID All Zeros 【发布时间】:2019-07-06 16:19:55 【问题描述】:

我继承了一个 Web 应用程序,其中一个后端 MS SQL 表有一个字段:

允许 Nulls = No,DataType = uniqueidentifier,DefaultValue = newid(),Condensed Data = Type uniqueidentifier

在数千行中,有些行的 GUID 为全零。它似乎不是旧数据,因为有些数据的创建日期最近。

当应用创建新记录时,SQL Server 没有在该字段中放置正确的 GUID 是怎么回事?

编辑:该字段的 EF 上下文有:

entity.Property(e => e.ThreadId).HasDefaultValueSql("newid()");

【问题讨论】:

也许应用程序本身正在插入零 Guids 插入以省略插入时的列?有了你提供的信息,你得到的只是疯狂的猜测 【参考方案1】:

uniqueidentifier 数据类型并不意味着它将是唯一的。如果您生成NEWID(),那么它会生成唯一的 id,但同样有可能生成相同的 id。

对于 0 的

insert into t values ('00000000-0000-0000-0000-000000000000');
insert into t values ('00000000-0000-0000-0000-000000000000');
insert into t values (newid());

陈述是有效的。如果您的 uid 列不是主键或具有唯一索引,则可以将重复键添加到表中。


如果您向表中添加检查约束,您可以限制并确定问题的根本原因

create table t (
  id uniqueidentifier unique
  CONSTRAINT CHK_uid CHECK (id != '00000000-0000-0000-0000-000000000000')
);
GO
insert into t values ('00000000-0000-0000-0000-000000000000');
insert into t values ('00000000-0000-0000-0000-000000000000');
insert into t values ('00000000-0000-0000-0000-000000000000');
insert into t values (newid());
GO
消息 547 级别 16 状态 0 第 1 行 INSERT 语句与 CHECK 约束“CHK_uid”冲突。冲突发生在数据库“fiddle_80c5a5fe96ab4e73ac5dafbb2256025d”、表“dbo.t”、列“id”中。 消息 547 级别 16 状态 0 第 2 行 INSERT 语句与 CHECK 约束“CHK_uid”冲突。冲突发生在数据库“fiddle_80c5a5fe96ab4e73ac5dafbb2256025d”、表“dbo.t”、列“id”中。 消息 547 级别 16 状态 0 第 3 行 INSERT 语句与 CHECK 约束“CHK_uid”冲突。冲突发生在数据库“fiddle_80c5a5fe96ab4e73ac5dafbb2256025d”、表“dbo.t”、列“id”中。 消息 3621 级别 0 状态 0 第 1 行 该语句已终止。 消息 3621 级别 0 状态 0 第 2 行 该语句已终止。 消息 3621 级别 0 状态 0 第 3 行 该语句已终止。
select * from t
GO
|编号 | | :------------------------------------------------ | | ddeb79f6-dc0f-4c6a-a065-2083d39a78c1 |

db小提琴here

【讨论】:

我必须承认我对约束的理解有点浅。当我将其设置为 PK、Identity 等时,我认为 SQL 为我制作了它们。当我通过 RT 单击查看表上的约束时,将脚本约束设置为 Create to New Query Window 我看到:ALTER TABLE [dbo].[MyTableName]为 [ThreadId] 添加默认值 (newid()) 如果你有PK,你不需要唯一约束但是0s的第二个约束仍然有效。当 insert 中没有提供值时使用默认值。如果我明确提供 guid 默认值将不起作用 该表有一个PK,但这不是它。看起来原始开发人员想要一个“cmets”表来保存跨应用程序的多个表/部分的所有 cmets。每个允许 cmets 的表都有一个 ThreadID(唯一标识符) cmets 表为使用此 ID 的各个部分保持一个正在运行的线程。其他表都没有 guid 的零。这个可以,但反过来,如果它全为零,则不会保存 cmets,因为 cmets 表本身不允许将全零输入其中。对不起,如果这令人困惑......我是。感谢您到目前为止的帮助。 我可以在事后添加不允许'00000000-0000-0000-0000-000000000000'的约束吗?我想是的,但还没有弄清楚。 是的,你可以。 ALTER TABLE t1 ADD CONSTRAINT CHK_uid CHECK (id != '00000000-0000-0000-0000-000000000000') 但首先你需要删除 0 个 uids【参考方案2】:

如果 SQL 列可以为空,则问题出在您的 C# 代码中。确保 POCO 类也使用可为空的 Guid。还要确保在创建新实例时初始化属性。不可为空的 Guid 的 C# 默认值是全零 Guid。如果问题只存在于旧数据,代码可能已经修复。

【讨论】:

如果你有一个像public int GUID get; set; 这样的属性并且你从未明确设置它,它的默认值为0(来自default(int))。 Allow Nulls 在表上设置为“否”。虽然我无法使用 Web UI 在应用程序的某处创建全为零的记录,但它一定会发生,因为我在不到一周前有全零的条目,并且在几周内没有更改应用程序的代码。 为什么不在表上创建唯一约束和检查约束?

以上是关于带有 GUID 全零的 MS SQL 表的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 EF Core 5 以使 MS SQL Server 数据库生成 Guid 密钥

sql如何将新产生的guid和一条其他表的数据插入当前表

如何在 ListObject 中显示 guid

SQL 表已经建立好了 如何在字段中插入GUID数据

sql 获取当前插入的主键 表主键是guid类型的

SQL GUID 与整数