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,
那么我错过了什么?
答案 0 :(得分:1)
它与继承没有任何共同之处 - 如果删除继承并将TableBase
属性复制到AppUser
,也会发生同样的情况。
问题在于AppUser
有2个自我引用 - UserInsert
和UserUpdate
。由于第一个被标记为必需而第二个是可选的,因此按照惯例,EF将它们映射到单个一对一FK关系,UserUpdate
是UserInsert
的反向导航属性。当然这不是你的意图。
通常,当EF常规映射不能产生所需结果时,您需要使用数据注释和/或流畅的API。在这种特殊情况下 - 流畅的API。最低要求是:
modelBuilder.Entity<AppUser>()
.HasOptional(e => e.UserInsert)
.WithMany();
通过这种方式,您告诉EF在一侧创建与UserInsert
引用导航属性的一对多关系,而在另一侧没有集合导航属性。这样做的附加效果是,当EF找到未映射的UserUpdate
引用导航属性时,按照惯例,它将创建另一个一对多单向关系。最后将创建两个FK列,与非自引用实体示例一样。
另请注意,在自引用实体AppUser
中,不能要求UserInsert
,否则您将无法创建任何AppUser
条记录。这就是我使用HasOptional
而不是HasRequired
的原因,它会覆盖该实体的基类属性Required
数据注释。