EF 4.1代码优先:如何以一对多的关系引用父代的子记录

时间:2011-11-01 18:06:23

标签: entity-framework foreign-keys code-first

我有一个简单的1:许多聚合关系,让我们说:

public class Parent
{
    public string Name {get; set;}
    public Child SelectedChild {get; set;}
    public Child PublishedChild {get; set;}
    public virtual ICollection<Child> AllChildren {get; set;}
}

public class Child
{
    public string Name {get; set;}
    [Required]
    public Parent Father {get; set;}
}

从此模型创建架构时,我收到错误:

在表'Parent'上引入FOREIGN KEY约束'Parent_SelectedChild'可能会导致循环或多个级联路径。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束

所以我将以下内容添加到OnModelCreating:

        modelBuilder.Entity<Child>()
            .HasRequired(v => v.Parent)
            .WithOptional(c => c.SelectedChild)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Child>()
            .HasRequired(v => v.Parent)
            .WithOptional(c => c.PublishedChild)
            .WillCascadeOnDelete(false);

这可以解决原始错误但我现在得到:

无法确定'xxx.Parent_SelectedChild'关系的主要结尾。 多个添加的实体可能具有相同的主键。

有人可以帮忙吗? 我本来想做的就是在父亲的1:多聚合关系中引用特定的子记录。我假设EF将在父节点上创建INT子id列,例如SelectedChild_Id&amp; PublishedChild_Id(或类似)。

提前致谢 -macon

编辑:回应@Slauma: 我可以使用:

获得生成的模式
            modelBuilder.Entity<Parent>()
            .HasOptional(p => p.SelectedChild)
            .WithOptionalPrincipal()
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Parent>()
            .HasOptional(p => p.PublishedChild)
            .WithOptionalPrincipal()
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Parent>()
            .HasMany(p => p.AllChildren)
            .WithRequired(c => c.Father)
            .WillCascadeOnDelete(false);

但是这会在子记录上生成多个FK,例如Parent_Id,Parent_Id1。我只想要一个从Parent到一个子行的引用,例如Parent_SelectedChildId。我是否必须使用父级的int列手动执行此操作?

1 个答案:

答案 0 :(得分:2)

我认为你有三个一对多的关系:

modelBuilder.Entity<Parent>()
    .HasOptional(p => p.SelectedChild)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Parent>()
    .HasOptional(p => p.PublishedChild)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Parent>()
    .HasMany(p => p.AllChildren)
    .WithRequired(c => c.Father)
    .WillCascadeOnDelete(false);

修改

我已经使用完全您在问题中提供的ParentChild类测试了上面的映射 - 唯一的例外是我添加了主键属性两个班级:public int Id { get; set; }。否则EF会抱怨缺少关键财产。此映射不会引发异常并在数据库中创建以下表:

家长表:

- Id                    int             not nullable (PK)
- Name                  nvarchar(MAX)   nullable
- SelectedChild_Id      int             nullable (FK)
- PublishedChild_Id     int             nullable (FK)

儿童表:

- Id                    int             not nullable (PK)
- Name                  nvarchar(MAX)   nullable
- Father_Id             int             not nullable (FK)

因此,预期有三个外键列。

由于您根据评论得到异常,我猜您测试的代码实际上存在一些重要差异。

BTW:将Parent类的两个导航属性映射为一对一关系,即使不是不可能,也要困难得多。在EF中,您需要在两个表之间使用共享主键来映射一对一关系,因此不可能将两个不同的实体分配给两个导航属性,因为它们不能都具有与父级相同的密钥。