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

Rob*_*Rob 5 c# entity-framework foreign-keys data-annotations ef-code-first

在我看来,该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; }
}
Run Code Online (Sandbox Code Playgroud)

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

INSERT语句与FOREIGN KEY约束"FK_dbo.Skills_dbo.BaseCards_BaseCardId"冲突.冲突发生在数据库"数据库",表"dbo.BaseCards",列"Id"中.

在我看来,像ForeignKeySkill试图以点IdBaseCards,而不是BaseCardId列,我想不通为什么..

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

存储更新,插入或删除语句会影响意外的行数(0).自实体加载后,实体可能已被修改或删除.刷新ObjectStateManager条目.

有谁知道我能得到这个代码的工作,所以财产BaseCardIdSkill类将指向BaseCardId的财产BaseCard,而不是表面上的Id财产?

提前致谢!

oct*_*ccl 9

您可以自己设置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; }
}
Run Code Online (Sandbox Code Playgroud)

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

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

现在,回到您的问题,在您的Context类中,您需要覆盖OnModelCreating方法以指定BaseCards表中Id的关系和no autogenerate列.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此配置,您必须始终使用不同的值设置BaseCard对象的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; }
}
Run Code Online (Sandbox Code Playgroud)

我的推荐是使用Fluent API,它更灵活,您不必触摸您的模型类.你可以在这篇文章中看到一些有用的消息


归档时间:

查看次数:

14812 次

最近记录:

11 年,8 月 前