直接用Guid.NewGuid()生成全局唯一GUID,它由操作系统密码学随机源驱动,线程安全且无需额外配置;new Guid()则返回全零值,不可混淆使用。

直接用 Guid.NewGuid() 就行,99% 的场景下这是唯一需要的操作。它不是“可能唯一”,而是由操作系统级密码学随机源驱动(Windows 用 BCryptGenRandom,Linux/macOS 用 /dev/urandom),无需你操心时间戳、进程 ID 或硬件指纹。
别把 new Guid() 当成新 ID
new Guid() 和 Guid.NewGuid() 完全是两回事:new Guid() 永远返回全零值 "00000000-0000-0000-0000-000000000000",等价于 Guid.Empty;而 Guid.NewGuid() 才真正生成随机 v4 GUID。
- 误用
new Guid()作主键,会导致数据库插入时所有记录共享同一个 ID,轻则主键冲突,重则数据覆盖 - EF Core 中若实体属性声明为
public Guid Id { get; set; }且没初始化,插入时实际传的是Guid.Empty,SQL Server 会报Cannot insert the value NULL into column 'Id'(即使字段非空) - 判断是否未设置,用
guid == Guid.Empty,不要用string.IsNullOrEmpty(guid.ToString())(永远 false)或guid.ToString() == ""(会抛NullReferenceException)
ToString() 格式选错,JSON 和 URL 就会出问题
GUID 默认转字符串是 "D" 格式(带短横线,36 字符),但不同场景要换格式,否则解析失败或浪费空间:
- 存数据库或做缓存 key:用
guid.ToString("N")→"a1b2c3d4e5f67890g1h2i3j4k5l6m7n8"(32 字符,无分隔符,小写) - 传给前端或写日志:保持默认
guid.ToString("D")或加.ToUpperInvariant()提高可读性 - 拼 SQL 字面量(如 SQL Server):用
guid.ToString("B")→"{a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8}" - 别用
guid.ToString().Replace("-", ""):多一次字符串分配,且原始 GUID 若为 null 会崩;也别试ToString("X")——这不是 GUID 支持的格式,直接抛FormatException
从字符串解析 GUID,必须用 TryParse
外部输入(比如 API 请求体、数据库查出的字符串)不可信,Guid.Parse() 遇到非法格式直接炸,而 Guid.TryParse() 返回 bool,安全可控:
-
Guid.TryParse("9b1deb4d3b584709850c61e63514d74f", out var g)→ 成功 -
Guid.TryParse("9b1deb4d-3b58-4709-850c-61e63514d74f", out var g)→ 同样成功(支持带/不带横杠、大小写、花括号) - 唯一硬要求:输入只能是 32 或 36 位合法十六进制字符 + 可选分隔符,不能含空格、下划线、中文等
- 如果必须基于字符串确定性生成 GUID(如测试固定值),得先哈希再截 16 字节:
Guid.CreateFromBytes(SHA256.HashData(Encoding.UTF8.GetBytes(input)).Take(16).ToArray()),别直接new Guid(input)
EF Core 主键配置不显式设,Guid.NewGuid() 就等于白写
在实体类里写 public Guid Id { get; set; } = Guid.NewGuid(); 看似稳妥,但有隐患:若该实体被反序列化(如从 JSON)、或通过构造函数绕过属性初始化,ID 仍可能是 Guid.Empty。更可靠的做法是用 Fluent API 显式控制:
- SQL Server:用
modelBuilder.Entity<myentity>().Property(e => e.Id).HasDefaultValueSql("NEWID()");</myentity> - PostgreSQL:配合
Npgsql,用HasDefaultValueSql("gen_random_uuid()") - 纯内存或跨平台:用
.ValueGeneratedOnAdd()+ 自定义ValueGenerator,确保每次 Add 都调Guid.NewGuid() - 迁移脚本里新增 Guid 主键列时,必须提供
defaultValue或defaultValueSql,否则已有数据行会因NOT NULL约束失败
最易被忽略的一点:GUID 是值类型,ToString("N") 每次都新建字符串对象。高频日志或缓存场景中,如果同一 GUID 要多次输出无横杠格式,缓存结果比反复调用更省 GC 压力。


















