【问题标题】:EF Core Seed Database OneToMany Relationship with predefined ListsEF Core 种子数据库 OneToMany 与预定义列表的关系
【发布时间】:2025-12-01 15:35:01
【问题描述】:

我正在尝试在我的数据库中使用已定义的 List 植入 OneToMany 关系,我得到以下错误消息

'无法添加实体类型'Country'的种子实体,因为它设置了导航'WineRegions'。要为关系播种,您需要将相关实体种子添加到“WineRegion”并指定外键值 {'CountryId'}。考虑使用 'DbContextOptionsBuilder.EnableSensitiveDataLogging' 来查看所涉及的属性值。'

我使用这个页面来创建我的课程: https://www.learnentityframeworkcore.com/relationships#one-to-many ...我只能猜测我需要手动定义键,即使它应该自动工作...

这是我的两节课。 WineRegions 包含一个 Country 和 Country 包含 WineRegions 的集合:

public class WineRegion
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int WineRegionId { get; set; }

    public string WineRegionName { get; set; }   

    public int CountryId { get; set; }
    public Country Country { get; set; }
}

public class Country
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CountryId { get; set; }

    [Required]
    [MaxLength(255)]
    public string CountryName { get; set; }

    [Required]
    [MaxLength(2)]
    public string ISO3166Alpha2 { get; set; }

    public ICollection<WineRegion> WineRegions { get; set; }
}

在播种期间,我不想使用硬编码的对象,例如(顺便说一句,此代码有效...):

        modelBuilder.Entity<Country>().HasData(
            new { Id = 1, Name = "France", ISO3166Alpha2 = "FR" }
            );

        modelBuilder.Entity<WineRegion>().HasData(
            new { Id = 1, Name = "Bordeaux", CountryId = 1 }
            );

正如我之前提到的,我想使用在 JSON 解析过程中生成的 List。

所以我就是这样做的:

        modelBuilder.Entity<Country>().HasData(listOfCountries);  // List<Country>
        modelBuilder.Entity<WineRegion>().HasData(listOfWineRegions); //List<WineRegion>

我的 JSON 如下所示:

  "wineregions": [
    {
      "id": 1,
      "country": "France",
      "iso2": "FR",
      "region": [
        {
          "id": 1,
          "name": "Bordeaux"
        },
        {
          "id": 2,
          "name": "Burgundy"
        },
        {
          "id": 4,
          "name": "Burgundy"
        },
        {
          "id": 5,
          "name": "Beaujolais"
        },
        {
          "id": 6,
          "name": "Champagne"
        },
        {
          "id": 7,
          "name": "Loire"
        },
        {
          "id": 8,
          "name": "Alsace"
        },
        {
          "id": 9,
          "name": "Rhône"
        },
        {
          "id": 10,
          "name": "Provence"
        },
        {
          "id": 11,
          "name": "Languedoc-Roussillon"
        },
        {
          "id": 12,
          "name": "Jura"
        }
      ]
    },
    {
      "id": 2,
      "country": "Italy",
      "iso2": "IT",
      "region": [
        {
          "id": 1,
          "name": "Piedmont"
        },
        {
          "id": 2,
          "name": "Barolo"
        },
        {
          "id": 3,
          "name": "Barbaresco"
        },
        {
          "id": 4,
          "name": "Tuscany"
        },
        {
          "id": 5,
          "name": "Veneto"
        },
        {
          "id": 6,
          "name": "Friuli-Venezia"
        },
        {
          "id": 7,
          "name": "Giulia"
        },
        {
          "id": 8,
          "name": "Abruzzo"
        },
        {
          "id": 9,
          "name": "Sicily"
        },
        {
          "id": 10,
          "name": "Lambrusco"
        }
      ]
    }
  ]
} 


Thanks in advance

【问题讨论】:

  • json无效,开头应该有{
  • 哦,那只是复制粘贴错误。很抱歉!
  • 问题解决了吗?

标签: c# asp.net one-to-many seeding ef-core-3.0


【解决方案1】:

您的WineRegionIdConutryId 是身份,由SQL 自动生成。

当您的数据库密钥是身份Id = 1 不起作用

您应该从CountryIdWineRegionId 中删除身份。

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CountryId { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int WineRegionId { get; set; }

另一种方式

你可以把你的代码改成这个。

Country country = new Country { Name = "France", ISO3166Alpha2 = "FR" };
modelBuilder.Entity<Country>().HasData(country);

modelBuilder.Entity<WineRegion>().HasData(
            new { Name = "Bordeaux", Country = country }
            );

在这种情况下ConutryIdWineRegionIdSQL 自动生成,ConutryWineRegion 之间的关系由该行创建

new { Name = "Bordeaux", Country = country/*<--NOTE THIS*/ }

【讨论】:

  • 感谢您的快速回复!我按照您推荐的方式更改了两个模型的 Id 列。现在我收到错误消息:无法添加实体类型“WineRegion”的种子实体,因为它设置了导航“国家”。要为关系播种,您需要将相关实体种子添加到“Country”并指定外键值 {'CountryId'}。考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看所涉及的属性值。
  • @bkDev 在sql 中将身份状态列更改为None 后,您是否检查了身份Id 的状态?更改后应禁用身份。
  • 我如何检查这个?我尝试了几件事,发现只要我删除 WineRegion 部分,国家部分就可以工作。这意味着我的国家表中有国家:)。现在我需要找出为什么 wineRegion 部分仍然崩溃
  • @bkDev 您可以在SQL Server 中查看。右键单击您的表格并选择设计。然后选择 Id 字段,然后在 Column Properties 并将 Identity Specification 设置为 No 。这个link 可能对你禁用身份有帮助
  • @bkDev 请记住,当您编辑模型时,您应该使用 Add-MigrationUpdate-database
【解决方案2】:

所以我想出了如何解决它,但我不完全明白为什么它必须是这样的...... 非常感谢 Farhad Zamani!

  1. 我将身份属性更改为:[DatabaseGenerated(DatabaseGeneratedOption.None)] -
  2. 我需要从两个类中删除 [Key] 属性
  3. 我需要将 [NotMapped] 属性应用到 WineRegion 类中的嵌套类 Country
  4. 我需要将 ForeignKey 属性应用于 CountryId 属性。

    public class WineRegion
    {
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int WineRegionId { get; set; }
    
    public string WineRegionName { get; set; }
    
    [NotMapped]
    public Country Country { get; set; }
    
    [ForeignKey("CountryId")]
    public int CountryId { get; set; }
    }
    
    public class Country
    {
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CountryId { get; set; }
    
    [Required]
    [MaxLength(255)]
    public string CountryName { get; set; }
    
    [Required]
    [MaxLength(2)]
    public string ISO3166Alpha2 { get; set; }
    
    public List<WineRegion> WineRegions { get; set; }
    }
    

【讨论】: