Code First 可选的一对一关系

Code First Optional One-To-One Relationship

为我有两个表(客户和用户)的情况编写模型。每个用户记录可能有一个可选的相关客户记录,反之亦然,但其中 none 是必须的。我发现 FK Associations 不是我需要的,但 Independent Associations 是。但我只能找到一种方法让它工作,我不断收到 'Unable to determine the principal end...The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.' 异常。

我的模型很简单:

public class User
{
    [Key]
    public int          Id              { get; set; }
    [StringLength(20)]
    public string       CustomerId      { get; set; }
    public string       Password        { get; set; }
    public bool         Locked          { get; set; }

    //[ForeignKey("CustomerId")]
    public virtual Customer Customer    { get; set; }
}

public class Customer
{
    [Key]
    [Column("Id", TypeName = "nvarchar")]
    [StringLength(20)]
    public string       Id              { get; set; }   //  nvarchar    20
    [Required]
    public string       GivenName       { get; set; }   //  nvarchar    100
    [Required]
    public string       Surname         { get; set; }   //  nvarchar    100

    //[InverseProperty("Customer")]
    public virtual User User            { get; set; }
}

我尝试添加 ForeignKeyAttribute 和 InversePropertyAttribute,它们目前已被注释掉,但它们也无济于事。如果在我的情况下可能的话,我更愿意使用数据注释而不是流利的 API。

一对一关系中,一端必须是主体,第二端必须是从属Principal end 是第一个插入的端,它可以在没有从属端的情况下存在。 Dependent 端是必须插入主体之后的端,因为它有主体的外键。配置一对一关系时,Entity Framework要求依赖的主键也为外key.This问题最简单的解决方法是在依赖[=上使用ForeignKey注解39=] 来识别它包含外键。在你的例子中,Customer 可能是依赖项,它的键 Customer.UserId 也应该是外键。但是两个键必须使用相同的类型声明:

public class User
{
   [Key]
   public int  Id  { get; set; }

   public virtual Customer Customer { get; set; }
}

public class Customer
{
   [Key, ForeignKey("User")]
   public int  UserId { get; set; }

   public virtual User User{ get; set; } 
}

我不知道如何使用 Data Annotations 解决您的问题,但是如果您想使用 Fluent Api,我认为关系的配置应该是这样的:

 modelBuilder.Entity<User>().HasOptional(u => u.Customer).WithOptionalPrincipal(c => c.User);

更新

我理解你的场景,但如果你有与你在模型中显示的相同的列,我认为你应该在数据库中映射一对多关系而不是一对一关系。尝试以这种方式映射您的关系:

public class User
{
    [Key]
    public int Id { get; set; }

    public string Password { get; set; }
    public bool Locked { get; set; }

    public string CustomerId { get; set; }

    [ForeignKey("CustomerId")]
    public virtual Customer Customer { get; set; }
}

public class Customer
{
    [Key]
    [Column("Id", TypeName = "nvarchar")]
    [StringLength(20)]
    public string Id { get; set; }   //  nvarchar    20
    [Required]
    public string GivenName { get; set; }   //  nvarchar    100
    [Required]
    public string Surname { get; set; }   //  nvarchar    100

    public virtual  ICollection<User> Users { get; set; }
}

请记住使用与数据库中相同的列名称映射您的属性。