Мне удалось заставить его работать, изменив его на эту модель:
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 является избыточным для квалификации, и нет способа обойти его, поскольку, как вы сказали, 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");
}
}
Что приводит к следующей схеме в БД:
Еще один способ избежать СУХОГО состоит в том, чтобы превратить иерархию в 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");
}
}
Что приводит к следующей схеме в БД: