EF Core 7.0.2操作SQLite:GUID查询存在数据却返回null
问题核心在于EF Core与SQLite处理Guid到字符串的转换格式不匹配:
SQLite没有原生Guid类型,你的数据库中Id字段存储为字符串格式,但EF Core默认会将Guid参数转换为小写无连字符的字符串(如9ec7d6a8b1c24d3e8f9a0b1c2d3e4f56)。如果数据库中实际存储的是带连字符的格式(如9EC7D6A8-B1C2-4D3E-8F9A-0B1C2D3E4F56)或大小写不一致,就会导致查询匹配失败,返回null。而RawSql直接使用传入的原始字符串Id,格式完全匹配,因此能正常查到数据。
方法1:配置实体属性的类型转换(推荐)
在DbContext的OnModelCreating方法中,为User的Id属性配置自定义的Guid-字符串转换规则,确保转换后的格式与数据库存储完全一致:
假设数据库中存储的是带连字符的小写字符串(如9ec7d6a8-b1c2-4d3e-8f9a-0b1c2d3e4f56),配置代码如下:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User>() .Property(u => u.Id) .HasConversion( guid => guid.ToString("D"), // Guid转字符串:带连字符的小写格式 str => Guid.Parse(str) // 字符串转Guid ); }
如果数据库中是带连字符的大写字符串,则修改转换逻辑为:
.HasConversion( guid => guid.ToString("D").ToUpperInvariant(), str => Guid.Parse(str) );
配置完成后,EF Core生成查询时会自动将Guid参数转换为匹配的字符串格式,即可正确命中数据库记录。
方法2:查询时手动转换格式(临时方案)
若不想修改实体配置,可在查询时手动将Guid转换为与数据库匹配的字符串格式,再进行比较:
public User GetUser(string Id) { if(Guid.TryParse(Id, out Guid result)) { // 转换为数据库存储的字符串格式(示例为带连字符的小写) string targetId = result.ToString("D"); var user = _context.Users.Include(x => x.Role) .SingleOrDefault(u => u.Id.ToString("D") == targetId); if(user != null) return user; } throw new Exception("User not found!"); }
注意:这种方法会让数据库端执行字符串转换操作,数据量大时可能影响性能,仅建议临时使用。
若要查看EF Core生成的SQL语句,需确保项目已配置Console日志提供者,在Program.cs中添加:
builder.Logging.AddConsole();
配置后,Microsoft.EntityFrameworkCore.Database.Command级别的日志会输出到控制台,可直观验证参数格式是否匹配。
内容的提问来源于stack exchange,提问作者AcidRod75

