简体   繁体   English

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

[英]How do I setup a one-to-one-or-zero relationship with Entity Framework AND expose the foreign key on the child entity?

I have a working configuration for a one-to-one relationship that looks like this: 我有一个适用于一对一关系的工作配置,如下所示:

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; }
}

This solution is in production and works perfectly. 该解决方案已投入生产,并且运行良好。 Now, I need to be able to reference the child entity from the parent entity, so I tried doing this: 现在,我需要能够从父实体引用子实体,所以我尝试这样做:

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

    public virtual ChildEntity Child { get; set; }
}

And I received this error: 我收到此错误:

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.

I've come across multiple solutions for how to configure the principle with the Fluent API, but nothing has allowed me to add the ChildEntity reference on ParentEntity and maintain the ParentId on the ChildEntity . 我已经遇到多个 解决方案如何与流利API配置原则,但一切都没有让我添加ChildEntity上参考ParentEntity和维护ParentIdChildEntity

In the first solution EF is creating an unidirectional one to many relationship. 在第一个解决方案中,EF正在创建单向一对多关系。 To help you understand better what is going on, the configuration of that relationship using Fluent Api would be: 为了帮助您更好地了解发生了什么,使用Fluent Api对该关系的配置如下:

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

Now, when you add the ChildEntity navigation property, EF understands you want to create a one-to one relationship. 现在,当您添加ChildEntity导航属性时,EF就会了解您想创建一对一的关系。 In an one to one relationship EF requires that the PK of the dependent entity also be the FK of the relationship: 在一对一关系中,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; }
}

But I don't think this is the model you are looking for because one ParentEntity could be parent of more than one ChildEntity , so in my opinion you need to configure an one to many relationship: 但是我不认为这是您要寻找的模型,因为一个ParentEntity可以是多个ChildEntityChildEntity ,所以我认为您需要配置一对多关系:

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; }
}

Update 更新

If you want to create an one to one relationship and both entities have their owns PKs, then you can't define a FK property in the dependent entity due to the restriction I explain at the beginning of my answer about the one to one relationships. 如果要创建一对一关系,并且两个实体都有自己的PK,则由于我在回答之初对一对一关系的解释的限制,因此无法在从属实体中定义FK属性。 A solution for what you need could be using a model like this: 您需要的解决方案可以使用如下模型:

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; }
}

Add this Fluent Api configuration to your context to specify who is the principal and the dependent in your relationship and also specify the name of the FK that you already have on your DB (you can't have a property on your entity with that name): 将此Fluent Api配置添加到您的上下文中,以指定谁是关系中的主体和从属,并指定数据库中已有的FK的名称(您的实体上不能使用该名称的属性) :

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

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

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