3

Zu meinem Modell zusammenfassen:Fremdschlüssel als TPH Scheider in EF4 mit CTP4-Code Ersten

  • Lizenz und Zertifikat sind Kinder Qualifikation
  • A Qualifikation hat einen und nur ein Beruf
  • Ein Beruf ist entweder eine lizenzierte Art (Typ 1) oder eine beglaubigte Art (Typ 2)

Anforderung: Sie sind die Beziehungen zwischen Unternehmen entiti ohne Redundanz in das Datenbankschema einzuführen. Art der Qualifikation (Lizenz/Zertifikat) muss dem Berufstyp entsprechen.

Hier ist mein vereinfachtes Modell, wie es derzeit steht - ich erklären, warum dies nicht unter funktioniert:

Public Class Profession 
    <Key()> 
    <DataMember(Order:=0)> 
    Public Property Type As Integer 
    <Key()> 
    <DataMember(Order:=1)> 
    Public Property Code As String 

    Public Property Title As String 
End Class 

Public Class Qualification 
    Public Property Id As Integer 
    Public Property PersonId As Integer 
    Public Property Type As Integer 
    Public Property ProfessionCode As String 
    Public Overridable Property Person As Person 
    Public Overridable Property Profession As Profession 
End Class 

Public Class License 
    Inherits Qualification 

    Public Property Number As String   
End Class 

Public Class Certificate 
    Inherits Qualification 

    Public Property IssuerName As String  
End Class 

Hier ist die vereinfachte Modelbuilder:

modelBuilder.Entity(Of Qualification) _ 
    .Property(Function(q) q.ProfessionCode).IsRequired() 

modelBuilder.Entity(Of Qualification) _ 
    .HasRequired(Of Profession)(Function(q) q.Profession) _ 
    .HasConstraint(Function(q, p) p.Type = q.Type AndAlso p.Code = q.ProfessionCode) 

modelBuilder.Entity(Of Qualification) _ 
    .MapHierarchy() _ 
    .Case(Of Qualification)(Function(q) New With { 
     q.Id, 
     q.PersonId, 
     q.ProfessionCode, 
     .Type = 0) _ 
    .Case(Of License)(Function(q) New With { 
     q.Number, 
     .Type = 1}) _ 
    .Case(Of Certificate)(Function(q) New With { 
     q.IssuerName, 
     .Type = 2}) _ 
    .ToTable("dbo.Qualifications") 

Der Grund, warum dies nicht der Fall ist Arbeit ist, dass EF4 does not allow FK-Eigenschaften als TPH-Diskriminator zu verdoppeln. Dies bedeutet, dass Typ nicht gleichzeitig ein Diskriminator und ein Fremdschlüsselfeld sein kann. Der Versuch, den Berufstyp in der HasConstraint-Methode für jede Entität fest zu programmieren, funktioniert auch nicht - dies erzeugt eine Ausnahme.

Eine mögliche Lösung wäre, einen Ersatzschlüssel zu Beruf hinzuzufügen, Typeigenschaft in Qualifikation zu entfernen und es durch ProfessionId FK zu ersetzen. Dies würde die Redundanzbedenken beseitigen, aber auch TPH zerstören. In der Tat bewegt sich der Diskriminator von der Qualifikation zum Beruf. Das Problem hier ist, dass ich keine Möglichkeit gefunden habe, Lizenz- und Zertifikatsobjekte zuzuordnen. Vielleicht kann ich stattdessen Ansichten zuordnen? Aber wie mache ich das in Code First?

So, jetzt bin ich mit einer Reihe von unappetitlichen Entscheidungen konfrontiert. Irgendwelche Vorschläge?

Antwort

1

schaffte ich es funktioniert zu machen, indem es zu diesem Modell zu ändern:

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"); 
    } 
} 

aber wie Sie sagen können, ProfessionType ist redundant auf Qualifikation, und es gibt keine Möglichkeit, es zu umgehen, da wie gesagt, Sie, EF würde SieFormal nicht einen Diskriminator als FK wieder zu verwenden, die sinnvoll, da diese Regel machen:

ein Beruf ist entweder eine genehmigte Art (Typ 1) oder eine zertifizierte Art (Typ 2)

ist etwas, das EF nicht bewusst ist, deshalb muss es es verhindern, um die Hierarchie zu schützen.

Persönlich würde ich das Objektmodell entwerfen, wie folgt, die ich denke, klarer und weniger redundant:

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"); 
    } 
} 

Welche dem folgenden Schema in DB-Ergebnisse: alt text

Noch eine andere Art und Weise zu vermeiden DRY wäre es, die Hierarchie zu drehen TPT sein statt 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"); 
    } 
} 


Welche dem folgenden Schema in DB-Ergebnisse:

alt text

+0

@Morteza, Vielen Dank für Ihren Beitrag. Ich hatte gehofft, es könnte einen besseren Weg geben, der DRY nicht verletzt. Wie Sie wissen, ist Type in dieser Lösung redundant. Würden Sie nur versuchen, dies durch Geschäftsregeln zu kontrollieren? – Antony

+0

* Steuern Sie dies durch Geschäftsregeln * Sie meinen, dass Sie überhaupt keine Diskriminatorspalte haben und schauen Sie einfach in der Qualifikationstabelle nach ProfessionType und finden Sie heraus, um welche Art von Objekt es sich handelt, richtig? –

+0

Ich habe noch einen anderen Weg hinzugefügt, DRY zu meiner Antwort zu vermeiden: TPT statt TPH. –

Verwandte Themen