返回文章列表

EF Core+Sqlite如何将自定义实体集合List<T>映射成JSON数组

2026-08-06

EF Core 可以将任何IEnumerable<T>属性(其中 T 是基元类型)映射到数据库中的JSON列。如:IEnumerable<int>,ICollection<string> 。但对于自定义实体集合,EF Core将默认新建另一张表做一对多外键关联,而不是映射成JSON数组存入当前表。可以通过使用内置JSON映射或配置值转换器来实现List<T>与JSON列的转换。

代码示例:将List<PinYinMeaning>属性映射为JSON数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class HanziContext:DbContext
{
    public DbSet<Hanzi> HanziTable => Set<Hanzi>();
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        =>optionsBuilder.UseSqlite($"Data Source=Hanzi.db");
}
public class Hanzi
{
    [Key]
    public string Text { get; set; } = "";
    public List<PinYinMeaning> PinYinMeanings { get; set; } = [];
}
public class PinYinMeaning
{
    public string PinYin { get; set; } = "";
    public string Meaning { get; set; } = "";
}

方法1:使用内置JSON映射,无需手写值转换器。在数据库上下文(HanziContext)中重写OnModelCreating方法。

1
2
3
4
5
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Hanzi>()
        .OwnsMany(hanzi => hanzi.PinYinMeanings, builder => builder.ToJson());
}

方法2:配置值转换器。在数据库上下文(HanziContext)中重写OnModelCreating方法。

1
2
3
4
5
6
7
8
9
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Hanzi>()
        .Property(h => h.PinYinMeanings)
        .HasConversion(
            v => JsonConvert.SerializeObject(v),
            v => JsonConvert.DeserializeObject<List<PinYinMeaning>>(v) ?? new List<PinYinMeaning>()
        );
}

注意:方法2中若直接在原列表中修改数据,EF Core无法侦测List内部元素变更,无法更新数据库。如:

1
2
3
var db = new HanziContext();
db.HanziTable.Find("阿").PinYinMeanings[0].Meaning = "another meaning";
db.SaveChanges();//无法更新数据库。

可以复制出整个集合,在其中更改数据后再替换原集合。如:

1
2
3
4
5
6
7
var db = new HanziContext();

var list = db.HanziTable.Find("阿").PinYinMeanings.ToList();
list[0].Meaning = "another meaning";

db.HanziTable.Find("阿").PinYinMeanings = list;
db.SaveChanges();
An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.