大小写不敏感的ValueComparer在未跟踪实体上调用Find时失效
Entity Framework Core 主键大小写不敏感配置后,未跟踪实体调用Find()返回null的问题
问题现象
为字符串类型主键配置了大小写不敏感的ValueComparer<string>后,调用Find()方法时出现不一致结果:
- 已被上下文跟踪的实体能正常匹配(如添加实体的上下文查询
"apple"可找到"Apple") - 新建上下文(未跟踪实体)调用
Find("apple")返回null
实体配置代码
modelBuilder.Entity<ProductEntity>().HasKey(e => e.Name); modelBuilder.Entity<ProductEntity>(e => { e.Property(p => p.Name).Metadata.SetValueComparer(new ValueComparer<string>( (s1, s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase), s => s.ToUpper().GetHashCode(), s => s )); });
测试代码
var builder = new DbContextOptionsBuilder<ShoppingListContext>(); builder.UseSqlite(ShoppingListContextFactory.SqliteConn.Value); var contextFirst = new ShoppingListContext(builder.Options); contextFirst.Database.EnsureCreated(); contextFirst.Products.Add(new ProductEntity { Name = "Apple" }); contextFirst.SaveChanges(); var contextSecond = new ShoppingListContext(builder.Options); Console.WriteLine(contextFirst.Products.Find("apple") is null); Console.WriteLine(contextSecond.Products.Find("apple") is null);
输出结果
False True
原因分析
ValueComparer仅作用于内存中已跟踪实体的比较逻辑,当Find()处理未跟踪实体时,会直接生成SQL查询数据库。SQLite默认采用大小写敏感的排序规则,因此数据库中存储的"Apple"与查询的"apple"无法匹配,导致返回null。
解决方案
方案1:配置数据库列的大小写不敏感排序规则
针对SQLite,可在属性配置时指定NOCASE排序规则,让数据库层面支持大小写不敏感查询,这样Find()生成的SQL会自动应用该规则:
modelBuilder.Entity<ProductEntity>().HasKey(e => e.Name); modelBuilder.Entity<ProductEntity>(e => { e.Property(p => p.Name) .UseCollation("NOCASE") // SQLite大小写不敏感排序规则 .Metadata.SetValueComparer(new ValueComparer<string>( (s1, s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase), s => s.ToUpper().GetHashCode(), s => s )); });
方案2:改用FirstOrDefault并手动指定匹配规则
如果无法修改数据库配置,可放弃Find(),使用FirstOrDefault()并显式指定大小写不敏感的匹配条件:
var product = contextSecond.Products.FirstOrDefault(p => string.Equals(p.Name, "apple", StringComparison.OrdinalIgnoreCase));
内容的提问来源于stack exchange,提问作者Daniel Michael Fabricius
相关产品推荐
相关产品推荐

