EF 6没有为某些类生成所有继承的字段

时间:2018-02-01 12:13:47

标签: c# entity-framework-6 sql-server-2016

public abstract class TableBase
{
    [Required]
    public DateTime DateInsert { get; set; }
    public DateTime? DateUpdate { get; set; }
    [Required]
    public AppUser UserInsert { get; set; }
    public AppUser UserUpdate { get; set; }        
}

public class AppUser:TableBase
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string LoginName { get; set; }
    [Required]
    public string PasswordStored { get; set; }        
}

public class SandorTestDBContext : DbContext
{
    public SandorTestDBContext() : base("SandorTestDB")
    {    
    }

    public DbSet<AppUser> AppUsers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
        base.OnModelCreating(modelBuilder);
    }
}

鉴于上述类,可以假设SQLserver中的AppUser表将包含这两个类的所有字段。但该表缺少UserUpdate_Id字段。

TABLE [dbo].[AppUsers](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[LoginName] [nvarchar](max) NOT NULL,
[PasswordStored] [nvarchar](max) NOT NULL,
[DateInsert] [datetime] NOT NULL,
[DateUpdate] [datetime] NULL,
[UserInsert_Id] [int] NOT NULL

另一方面,添加以下类:

public class Company : TableBase
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string OldCompanyReference { get; set; }  
}

在Context中添加DbSet会生成所有字段

public DbSet<Company> Companies { get; set; }

TABLE [dbo].[Companies](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[OldCompanyReference] [nvarchar](max) NULL,
[DateInsert] [datetime] NOT NULL,
[DateUpdate] [datetime] NULL,
[UserInsert_Id] [int] NOT NULL,
[UserUpdate_Id] [int] NULL,

那么我错过了什么?

1 个答案:

答案 0 :(得分:1)

它与继承没有任何共同之处 - 如果删除继承并将TableBase属性复制到AppUser,也会发生同样的情况。

问题在于AppUser有2个自我引用 - UserInsertUserUpdate。由于第一个被标记为必需而第二个是可选的,因此按照惯例,EF将它们映射到单个一对一FK关系,UserUpdateUserInsert的反向导航属性。当然这不是你的意图。

通常,当EF常规映射不能产生所需结果时,您需要使用数据注释和/或流畅的API。在这种特殊情况下 - 流畅的API。最低要求是:

modelBuilder.Entity<AppUser>()
    .HasOptional(e => e.UserInsert)
    .WithMany();

通过这种方式,您告诉EF在一侧创建与UserInsert引用导航属性的一对多关系,而在另一侧没有集合导航属性。这样做的附加效果是,当EF找到未映射的UserUpdate引用导航属性时,按照惯例,它将创建另一个一对多单向关系。最后将创建两个FK列,与非自引用实体示例一样。

另请注意,在自引用实体AppUser中,不能要求UserInsert,否则您将无法创建任何AppUser条记录。这就是我使用HasOptional而不是HasRequired的原因,它会覆盖该实体的基类属性Required数据注释。