我设法通过将其更改为此模型使其工作:
public class Profession {
[Key][DataMember(Order = 0)]
public int Type { get; set; }
[Key][DataMember(Order = 1)]
public string Code { get; set; }
public string Title { get; set; }
}
public class Qualification {
public int Id { get; set; }
[Required]
public int ProfessionType { get; set; }
[Required]
public string ProfessionCode { get; set; }
[Required]
public virtual Profession Profession { get; set; }
}
public class License : Qualification {
public string Number { get; set; }
}
public class Certificate : Qualification {
public string IssuerName { get; set; }
}
class Context : DbContext {
public DbSet<Qualification> Qualifications { get; set; }
public DbSet<Profession> Professions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Qualification>()
.HasRequired<Profession>(q => q.Profession)
.HasConstraint((q, p) => q.ProfessionCode == p.Code
&& q.ProfessionType == p.Type);
modelBuilder.Entity<Qualification>().MapHierarchy()
.Case<Qualification>(q => new {
q.ProfessionCode,
q.ProfessionType,
q.Id,
Type = 0
}).Case<License>(q => new {
q.Number,
Type = 1
}).Case<Certificate>(q => new {
q.IssuerName,
Type = 2
}).ToTable("Qualifications");
}
}
但是,正如您所知,ProfessionType 在 Qualification 中是多余的,并且没有办法解决它,因为就像您说的那样,EF 不允许您将鉴别器重用为 FK,因为这条规则是有意义的:
专业是许可类型(类型 1)或认证类型(类型 2)
是 EF 不知道的,因此它必须阻止它以保护层次结构。
就个人而言,我会按如下方式设计对象模型,我认为这样更清晰,更少冗余:
public class Profession {
public int ProfessionId { get; set; }
public int Type { get; set; }
public string Code { get; set; }
public string Title { get; set; }
}
public class Qualification {
public int Id { get; set; }
public int ProfessionId { get; set; }
[Required]
public virtual Profession Profession { get; set; }
}
public class License : Qualification {
public string Number { get; set; }
}
public class Certificate : Qualification {
public string IssuerName { get; set; }
}
class Context : DbContext {
public DbSet<Qualification> Qualifications { get; set; }
public DbSet<Profession> Professions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Qualification>()
.HasRequired<Profession>(q => q.Profession)
.HasConstraint((q, p) => q.ProfessionId == p.ProfessionId);
modelBuilder.Entity<Qualification>().MapHierarchy()
.Case<Qualification>(q => new {
q.ProfessionId,
q.Id,
Type = 0
})
.Case<License>(q => new {
q.Number,
Type = 1
})
.Case<Certificate>(q => new {
q.IssuerName,
Type = 2
})
.ToTable("Qualifications");
}
}
这导致 DB 中的以下模式:
避免 DRY 的另一种方法是将层次结构转换为 TPT 而不是 TPH:
public class Profession {
[Key]
[DataMember(Order = 0)]
public int Type { get; set; }
[Key]
[DataMember(Order = 1)]
public string Code { get; set; }
public string Title { get; set; }
}
public class Qualification {
public int Id { get; set; }
[Required]
public int ProfessionType { get; set; }
[Required]
public string ProfessionCode { get; set; }
[Required]
public virtual Profession Profession { get; set; }
}
public class License : Qualification {
public string Number { get; set; }
}
public class Certificate : Qualification {
public string IssuerName { get; set; }
}
class Context : DbContext
{
public DbSet<Qualification> Qualifications { get; set; }
public DbSet<Profession> Professions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Qualification>()
.HasRequired<Profession>(q => q.Profession)
.HasConstraint((q, p) => q.ProfessionCode == p.Code
&& q.ProfessionType == p.Type);
modelBuilder.Entity<Qualification>().MapHierarchy(q => new
{
q.Id,
q.ProfessionCode,
q.ProfessionType,
})
.ToTable("Qualifications");
modelBuilder.Entity<License>().MapHierarchy(l => new
{
l.Id,
l.Number
})
.ToTable("Licenses");
modelBuilder.Entity<Certificate>().MapHierarchy(c => new
{
c.Id,
c.IssuerName
})
.ToTable("Certificates");
}
}
这导致 DB 中的以下模式: