Entity Framework 6 在第 3 级子表中编码第一个一对多关系

Entity Framework 6 Code first One-to-Many relation in 3rd level child tables

我有 ApplicationUser table 由 ASP.NET 身份框架创建,我想使用另一个 table 客户 one-to-one relationApplicationUsertable的PK是字符串类型的IdCustomer table 有一个 FK 类型的字符串。我不允许更改 ApplicationUser table 的 Id 类型。但是客户 table 必须有一个 int 类型的身份(自动编号)列。这很好。

然后这个 Customer table 与 Contact table 有 one-to-many 关系。

CustomerContact table 都有唯一标识列 IdContact table 有一个 CustomerId 列。如果没有 AspNetUser table,代码首先使用这些 idCustomerId 列生成 one-to-many 关系。由于 AspNetuser table 与 Customerone-to-one 关系,因此不使用 CustomerId。但是代码首先生成自己的字符串键 (Customer_UserId) 来构建这个 one-to-many 关系。

如何使用 Customer table 列关联 Contact table 和 CustomerId 列以使用 EF6 代码优先方法映射关系?

完整代码如下:

应用程序用户

public class ApplicationUser : IdentityUser
{
    //Navigation   properties
    public Customer Customer { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

客户

public class Customer
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Index(IsUnique = true)]
    public int Id { get; set; }

    [Key, ForeignKey("ApplicationUser")]
    public string UserId { get; set; }

    public string BusinessName { get; set; }

    //Navigation properties
    [ForeignKey("UserId")]
    public ApplicationUser ApplicationUser { get; set; }
    public virtual ICollection<Contact> Contacts { get; set; }
}

联系

public class Contact
{
    public int Id { get; set; }
    public int CustomerId { get; set; }

    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string OfficeLocation { get; set; }
    //Navigation properties
    [Required]
    public Customer Customer { get; set; }

}

ApplicationDbContext

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(): base("DefaultConnection", throwIfV1Schema: false){}

    static ApplicationDbContext()
    {
        // Set the database intializer which is run once during application start
        // This seeds the database with admin user credentials and admin role
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Customer>()
            .HasRequired(u => u.ApplicationUser).WithRequiredDependent(c => c.Customer);
    }

    public System.Data.Entity.DbSet<WebServer.Models.Customer> Customers { get; set; }

    public System.Data.Entity.DbSet<WebServer.Models.Contact> Contacts { get; set; }
}

我发现删除显式外键并删除联系人的 'Customer' 属性 显着改变了架构。

这将删除 Customer_UserId

看起来这就是您所追求的行为。

我明白了。 ApplicationUserCustomer table 是 one-to one 所以两个 table 有相同的 PKString IdApplicationUserCustomer 中的 String UserId)。从逻辑上讲,我们可以将这两个 table 视为一个 table 和 PK 类型 stringContact table 是 Customer table 的子代。因此CustomerContact之间存在one-to-many关系。因此 Contact table 必须有一个 Foreign Key 类型的字符串。所以模型中的 CustomerId 应该是 string 而不是 int 的类型。此外,为了指示代码优先使用此字段,我需要将 [ForeignKey("CustomerId")] 属性添加到 public Customer Customer { get; set; } 属性.

所以新的Contact模型应该是这样的

public class Contact
{
   public int Id { get; set; }
   public string CustomerId { get; set; }
   public string LastName { get; set; }
   public string FirstName { get; set; }
   public string OfficeLocation { get; set; }

   //Navigation properties

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

PS:在我原来的应用程序中,我在这个 table 层次结构中有另一个级别。一个联系人可以有多个地址,所以 Address table 可以使用类型 intFKContacts PK 组成另一个 one-to-many关系。