如何与实体框架建立一对一或零关系并在子实体上公开外键?

时间:2015-07-28 13:56:20

标签: c# asp.net entity-framework

我有一个一对一关系的工作配置,如下所示:

public class ParentEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; } 
}

public class ChildEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Required]
    public Guid ParentId { get; set; }

    [ForeignKey("ParentId")]
    public ParentEntity Parent { get; set; }
}

此解决方案正在生产中并且运行良好。现在,我需要能够从父实体引用子实体,所以我尝试这样做:

public class ParentEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public virtual ChildEntity Child { get; set; }
}

我收到了这个错误:

System.InvalidOperationExceptionUnable to determine the principal end of an association between the types 'ChildEntity' and 'ParentEntity'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

我遇到了https://github.com/braincorp/gstreamer_ios_tutorial multiple有关如何使用Fluent API配置原则的信息,但没有任何内容允许我在{{1}上添加ChildEntity引用并保留ParentEntity上的ParentId

1 个答案:

答案 0 :(得分:3)

在第一个解决方案中,EF正在创建单向一对多关系。为了帮助您更好地了解正在发生的事情,使用Fluent Api配置该关系将是:

modelBuilder.Entity<ChildEntity>()
            .HasRequired(ce=>ce.Parent)
            .WithMany()
            .HasForeignKey(ce=>ce.ParentId);

现在,当您添加ChildEntity导航属性时,EF了解您要创建一对一的关系。在一对一关系中,EF要求从属实体的PK也是关系的FK:

public class ParentEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; } 
    public virtual ChildEntity Child { get; set; }
}

public class ChildEntity
{
    [Key, ForeignKey("Parent")]
    public Guid Id { get; set; }

    public ParentEntity Parent { get; set; }
}

但我认为这不是您要寻找的模型,因为一个ParentEntity可能是多个ChildEntity的父级,所以在我看来,您需要配置一对多的关系:

public class ParentEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; } 

    public virtual ICollection<ChildEntity> Children { get; set; }
}

public class ChildEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [ForeignKey("Parent")]
    public Guid ParentId { get; set; }

    public ParentEntity Parent { get; set; }
}

更新

如果你想创建一对一的关系,并且两个实体都拥有自己的PK,那么你就不能在依赖实体中定义一个FK属性,因为我在答案的开头解释了一个关于一个关系。您需要的解决方案可能是使用这样的模型:

public class ParentEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; } 
    public virtual ChildEntity Child { get; set; }
}

public class ChildEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public ParentEntity Parent { get; set; }
}

将此Fluent Api配置添加到您的上下文,以指定您的关系中的主体和从属人员,并指定您在数据库中已有的FK的名称(您的实体上不能拥有属性)那个名字):

modelBuilder.Entity<ChildEntity>()
            .HasRequired(sr => sr.Parent)
            .WithOptional(s => s.Child)
            .Map(c=>c.MapKey("Parent_Id"));