You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过EF Core将Foo类的List<string> Types属性转为SQL Server表

完整解决方案:将Foo的Types列表存入独立SQL Server表

1. 修正实体类定义

首先需要补充FooType实体类,并调整Foo类的属性结构,确保EF Core能识别实体关系:

// FooType实体:对应数据库中的FooTypes表
public class FooType
{
    public int FooId { get; set; }
    public string Type { get; set; }

    // 导航属性:关联到对应的Foo
    public Foo Foo { get; set; }
}

// Foo实体:调整后适配EF Core关系映射
public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    // 其他原有属性...

    // 【可选】如果需要直接接收API的Types数据,添加非映射属性
    [NotMapped]
    public List<string> Types { get; set; }

    // EF Core导航属性:关联当前Foo对应的所有FooType
    public List<FooType> FooTypes { get; set; } = new List<FooType>();
}

2. 完善DbContext配置

你的原配置缺少关键的实体属性关联和约束,以下是修正后的完整配置:

public class FooDbContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<FooType> FooTypes { get; set; }

    // 构造函数:传入数据库连接配置
    public FooDbContext(DbContextOptions<FooDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置Foo实体
        modelBuilder.Entity<Foo>()
            .HasKey(f => f.Id); // 主键为Id

        modelBuilder.Entity<Foo>()
            .ToTable("Foos")
            .Property(f => f.Name)
            .HasMaxLength(50)
            .IsRequired(); // 标记Name为必填字段

        // 配置FooType实体
        modelBuilder.Entity<FooType>()
            .HasKey(ft => new { ft.FooId, ft.Type }); // 复合主键:避免同一Foo下重复存储相同Type

        modelBuilder.Entity<FooType>()
            .ToTable("FooTypes")
            .Property(ft => ft.Type)
            .HasMaxLength(100)
            .IsRequired(); // 标记Type为必填字段

        // 配置一对多关系:一个Foo对应多个FooType
        modelBuilder.Entity<Foo>()
            .HasMany(f => f.FooTypes)
            .WithOne(ft => ft.Foo)
            .HasForeignKey(ft => ft.FooId)
            .OnDelete(DeleteBehavior.Cascade); // 删除Foo时自动删除关联的FooType(可根据需求调整为Restrict)
    }
}

3. 处理API数据的转换与存储

从API获取JSON并反序列化后,需要将Types列表转换为FooType实体集合,再通过EF Core保存到数据库:

方式一:直接使用带[NotMapped]属性的Foo类

// 从API获取JSON并反序列化为Foo列表
string apiJson = await new HttpClient().GetStringAsync("your-api-url");
var fooList = JsonSerializer.Deserialize<List<Foo>>(apiJson);

// 将每个Foo的Types转换为FooType对象
foreach (var foo in fooList)
{
    if (foo.Types != null)
    {
        foreach (var type in foo.Types)
        {
            foo.FooTypes.Add(new FooType { Type = type });
        }
        foo.Types = null; // 清空非映射属性
    }
}

// 保存到数据库
using (var context = new FooDbContext(options))
{
    context.Foos.AddRange(fooList);
    await context.SaveChangesAsync();
}

方式二:使用DTO分离API数据与实体类(更推荐)

如果不想修改原有Foo类的结构,可以创建DTO类接收API数据,再映射到实体:

// API数据接收DTO
public class FooDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    // 其他API返回属性...
    public List<string> Types { get; set; }
}

// 反序列化并映射
string apiJson = await new HttpClient().GetStringAsync("your-api-url");
var dtoList = JsonSerializer.Deserialize<List<FooDto>>(apiJson);

var fooList = dtoList.Select(dto => new Foo
{
    Id = dto.Id,
    Name = dto.Name,
    // 其他属性映射...
    FooTypes = dto.Types?.Select(t => new FooType { Type = t }).ToList() ?? new List<FooType>()
}).ToList();

// 保存到数据库
using (var context = new FooDbContext(options))
{
    context.Foos.AddRange(fooList);
    await context.SaveChangesAsync();
}

关键说明

  • 原配置的核心问题是缺少FooType实体定义,且Foo类没有对应的导航属性FooTypes,导致EF无法识别关系
  • 复合主键{FooId, Type}确保同一Foo下不会重复存储相同的Type值
  • 可以根据业务需求调整OnDelete行为(比如DeleteBehavior.Restrict禁止删除关联了FooType的Foo)

内容的提问来源于stack exchange,提问作者Bruno S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 06:13:14