实体框架代码第一个外键问题
本文关键字:问题 第一个 框架 代码 实体 | 更新日期: 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
试图指向 BaseCards
的Id
列而不是BaseCardId
列,我不知道为什么......
如果我尝试删除 BaseCard
的"正常"Id
属性,并将BaseCardId
设置为 PK(属性为 [Key]
),则会出现以下错误:
存储更新、插入或删除语句影响了意外的行数 (0)。自加载实体以来,实体可能已被修改或删除。刷新对象状态管理器条目。
有谁知道我如何让这段代码工作,以便来自 Skill
类的属性BaseCardId
指向 BaseCard
的BaseCardId
属性,而不是显然是 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,它更灵活,你不必接触你的模型类。您可以在这篇文章中看到一些有用的合作