实体框架代码第一个外键问题

本文关键字:问题 第一个 框架 代码 实体 | 更新日期: 2023-09-27 18:35:21

在我看来,ForeignKey属性对我不起作用,但我想我用错了;)

用代码更容易解释:

public class BaseCard
{
    public int Id {get ; set; }
    public int BaseCardId { get; set; }
    public List<Skill> Skills { get; set; }
}
public class Skill
{
    public int Id { get; set; }
    public int BaseCardId { get; set; }
    [ForeignKey("BaseCardId")]
    public BaseCard BaseCard { get; set; }
}

当我尝试用种子方法填充这些对象时,出现此错误:

插入语句与外键约束"FK_dbo冲突。Skills_dbo。BaseCards_BaseCardId"。冲突发生在数据库"数据库",表"dbo"中。底卡",列"Id"。

在我看来,Skill 中的ForeignKey试图指向 BaseCardsId列而不是BaseCardId列,我不知道为什么......

如果我尝试删除 BaseCard 的"正常"Id属性,并将BaseCardId设置为 PK(属性为 [Key]),则会出现以下错误:

存储更新、插入或删除语句影响了意外的行数 (0)。自加载实体以来,实体可能已被修改或删除。刷新对象状态管理器条目。

有谁知道我如何让这段代码工作,以便来自 Skill 类的属性BaseCardId指向 BaseCardBaseCardId属性,而不是显然是 Id 属性?

提前感谢!

实体框架代码第一个外键问题

您可以自己设置 BaseCard 的 ID,但首先您必须使用 Fluent API 来指定此和一对多关系。此外,这样,您就不必在模型类中指定属性。您的模型类如下所示:

public class BaseCard
{
  public int Id {get ; set; }
  public virtual ICollection<Skill> Skills { get; set; }
}
public class Skill
{
  public int Id { get; set; }
  public int BaseCardId { get; set; }
  public virtual BaseCard BaseCard { get; set; }
}

如您所见,我将导航属性更改为虚拟。如果将导航属性定义为虚拟 EF,则会在运行时创建一个派生自 BaseCard 类的新类(动态代理)并改用它(技能也会发生同样的情况)。这个新的动态创建的类包含首次访问时加载导航属性的逻辑。此功能称为延迟加载。它使实体框架能够避免从数据库中加载不需要的依赖对象的整个树。可以在以下帖子中找到有关此主题的详细信息:为什么导航属性在 EF 和实体框架 4.1 虚拟属性中默认为虚拟属性。

我在您的模型中提出的另一个更改是在"技能"属性中使用 ICollection<> 类型而不是 List<>。正如你在这篇文章中看到的,在这种情况下,接口是一个很好的做法。它允许您稍后指定所需的实现(可以是 List<>)。

现在,回到你的问题,在你的上下文类中,你需要重写 OnModelCreate 方法来指定关系和 BaseCard 表中 Id 的无自动生成列。

public class YourContext : DbContext
{
    public DbSet<BaseCard> BaseCards { get; set; }
    public DbSet<Skill> Skill { get; set; }
    //...
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure the primary key for BaseCard
        modelBuilder.Entity<BaseCard>().HasKey(t => t.Id);
        //specify no autogenerate the Id Column
        modelBuilder.Entity<BaseCard>().Property(b => b.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        //one-to-many relationship 
        modelBuilder.Entity<Skill>().HasRequired(c => c.BaseCard)
                .WithMany(s => s.Skills)
                .HasForeignKey(c => c.BaseCardId);
    }
}

使用此配置时,必须始终使用不同的值设置基本卡对象的 Id。

如果您更喜欢使用数据注释,可以通过以下方式指定相同的注释:

public class BaseCard
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }
    public virtual ICollection<Skill> Skills { get; set; }
}
public class Skill
{
    [Key]
    public int Id { get; set; }
    public int BaseCardId { get; set; }
   [ForeignKey("BaseCardId")]
    public virtual BaseCard BaseCard { get; set; }
}

我的建议是使用Fluent API,它更灵活,你不必接触你的模型类。您可以在这篇文章中看到一些有用的合作