文章目录
背景
痛点
ABP使用ExtraProperties实现动态字段,它通常是以json文本的形式存在数据库里,如果将动态字段作为where条件去查,通常会调用json_value。即使这样在没有索引加持下也会很慢。
破局
简而言之就是postgresql里的gin+jsonb,但是无论是EF还是Dapper都不支持jsonb进行查询。(我试了不行,各位可以再试试)
sql
select * from "Books" b where b."ExtraProperties"->>'出版社'='新华书店';
select * from "Books" b where b."ExtraProperties"->>'SomeTime' > '2025-12-31';
最终还是选择了SqlSugar
Coding
OnModelCreating
原则上我们还是要用EF Code First创建数据库的。但是要修改一下OnModelCreating
csharp
builder.Entity<Book>(b =>
{
b.ToTable("Books");
//Configure the base properties
b.ConfigureByConvention();
//Configure other properties (if you are using the fluent API)
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.Property(x => x.ExtraProperties).HasColumnType("jsonb")
.HasConversion(
v => JsonSerializer.Serialize(v),
v => JsonSerializer.Deserialize<ExtraPropertyDictionary>(v)
)
.HasDefaultValueSql("'{}'::jsonb");
});
修改Book
为了让SqlSugar知道某个字段是json字段,还要给字段加IsJson标注,可以在entity上加,也可以在dto上加。具体取决于你用哪个类去接
csharp
public class Book : FullAuditedAggregateRoot<Guid>
{
public Book() { }
public Book(Guid id) : base(id) { }
public string Name { get; set; }
[SugarColumn(IsJson = true)]
public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
}
创建API
csharp
public virtual async Task<IActionResult> GetBook()
{
var books = _sugarDb.Db.Ado.SqlQuery<Book>(@"select * from ""Books"" b where b.""ExtraProperties""->>'出版社'=@store;",
new { store = "新华书店" }).ToList();
//这样查询还是会报错
//var books = _sugarDb.Db.Queryable<Book>().Where(b => SqlFunc.JsonField(b.ExtraProperties, "出版社") == "新华书店").ToList();
return new JsonResult(books);
}