繁体   English   中英

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

[英]Entity Framework Code First Foreign Key issue

在我看来, 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; }
}

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

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

在我看来,像SkillForeignKey试图指向BaseCardsId列而不是BaseCardId列,我无法弄清楚为什么..

如果我尝试删除BaseCard的“普通” Id属性, BaseCard设置为PK(具有属性[Key] ), BaseCardId出现以下错误:

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

有谁知道我能得到这个代码的工作,所以物业BaseCardIdSkill类将指向BaseCardId财产BaseCard ,而不是明显的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类派生的新类(动态代理)并使用它(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);
    }
}

使用此配置,您必须始终使用不同的值设置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; }
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM