2017-12-11 5 views
1

Ich habe ein Problem, ich versuche, mit dem Entity Framework 6.0 zu lösen und hoffe, dass jemand hier eine Richtung geben kann. Ich fühle mich mit ADO.NET viel wohler aber möchte dieses Projekt in EF machen.So definieren Sie Fremdschlüsselbeziehungen in Entity Framework anders als die Standardmethode

Ich habe ein Objekt namens Politik und eine andere namens Payplan

public class Policy 
{ 
    //Various properties not relevant 

    public PayPlan PaymentPlan { get; set; } 
} 

public class PayPlan 
{ 
    public int PayPlanId { get; set;} 

    public string Description { get; set; } 
} 

Wie Sie in diesem Beispiel sehen können, ein Payplan ist ein Kind-Objekt für eine Politik. Es kann null sein oder eine einzelne Instanz eines PayPlans, der einer Richtlinie zugeordnet ist.

Wenn ich den Model Builder ausführe, erstellt er die Tabellen und fügt einen Fremdschlüssel in die Richtlinientabelle für den Datensatz im PayPlan ein. Dies funktioniert nicht wirklich für mich, denn 1) Ich möchte das Db-Schema ähnlich einer früheren Version der Anwendung, in der die PolicyId ist ein ForeignKey in die PayPlan und 2) Mit Cascading Deletes, wenn die PayPlan gelöscht werden würde würde die Politik mitnehmen und ich brauche das anders herum. Die Richtlinie ist das Stammobjektformular, das alle anderen Objekte im DB ihre Beziehungen zeichnen. PayPlan, btw, ist nur ein Beispiel für diese Diskussion, aber im eigentlichen Projekt würde das Policy-Objekt eine Anzahl von untergeordneten Objekten enthalten, die auf ähnliche Weise mit ihm verknüpft sind.

Meine Frage, wie kann ich dies einrichten, entweder durch Datenanmerkungen oder über die Fluent-API, um das von mir beschriebene Schema zu erreichen?

+0

Wenn Sie Payplan wollen FK-Politik zu haben, sollte nicht dann da sein "PayPlan.Policy" -Eigenschaft und nicht "Policy.PaymentPlan"? Mit dem aktuellen Modell kann ein PayPlan mehreren Richtlinien zugeordnet werden, die nicht mit den Anforderungen in der Datenbank kompatibel sind. Randnotiz: Wenn Sie eine vorhandene Datenbank haben, ist es möglicherweise einfacher, Ihr Modell daraus zu generieren und nicht zuerst mit dem Code zu replizieren. – Evk

+0

Das würde für mich bedeuten, dass die Politik dem PayPlan untergeordnet war und nicht umgekehrt. Schließlich könnte ein PayPlan in diesem Beispiel eine Null-Policy haben, was eine Unmöglichkeit wäre, da ein PayPlan nur wie in der Policy definiert existieren würde, aber es wäre durchaus akzeptabel, wenn eine Police keinen Payplan hätte. –

+0

Ich höre Sie auf dem Db. Der existierende Db ist ungefähr 8 Jahre alt und das Produkt von 11 verschiedenen Leuten, die während dieser Zeit daran arbeiteten, verschiedene Pflaster anzuwenden. Ich möchte die Datenbank aufräumen. Aber Sie können immer noch einen Punkt haben, in dem ich zuerst das neue Db schreiben/definieren und dann das Modell bauen könnte. –

Antwort

1

So, nach ein wenig über dies auf EF Graben 6, nachdem Sie erwähnten Sie diese Version verwenden und fanden diese:

Anscheinend alternativen Schlüssel nicht auf EF 6. Wie @rowanmiller auf dieser Github Ausgabe unterstützt:

Leider ist dies eine Einschränkung von EF6. Sie können keine ausländische Schlüsseleigenschaft in einer Eins-zu-Eins-Beziehung haben, es sei denn, es ist auch die Primärschlüsseleigenschaft . Dies liegt im Wesentlichen daran, dass EF6 alternative Schlüssel/eindeutige Indizes nicht unterstützt. Daher können Sie nicht erzwingen, dass eine nicht primäre Schlüsseleigenschaft eindeutig ist. Die Tatsache, dass Sie es tun können, wenn die ausländische Schlüsseleigenschaft nicht in der Entität ist, ist ein bisschen eine Eigenart ... aber offensichtlich nicht etwas, das wir entfernen würden: smile :.

BTW alternative Schlüssel (und daher dieses Szenario) wird in EF Core unterstützt.

Mapping foreign key in HasOptional().WithOptionalDependent() relation

Sie können immer noch die FK, wie Sie wollen, aber Sie können die FK Eigentum auf Ihrer PayPlan Klasse nicht haben. Wenn Sie das tun, werden Sie mit zwei FKs enden. Also, wenn Sie Ihre Beziehung wie folgt konfiguriert werden:

public class Policy 
{ 
    public int PolicyId { get; set; } 

    public string Description { get; set; } 

    public PayPlan PaymentPlan { get; set; } 
} 

public class PayPlan 
{ 
    public int PayPlanId { get; set; } 
    public string Description { get; set; } 
    public Policy Policy { get; set; } 
} 


protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<PayPlan>() 
     .HasOptional(a => a.Policy) 
     .WithOptionalDependent(p => p.PaymentPlan) 
     .WillCascadeOnDelete(true); 
} 

Sie mit diesem auf SQL Ende:

enter image description here

Wußte nicht darüber, da ich nie dieses Szenario hatte. Saugt viel. ABER du kannst es immer noch mit EF Core machen :), was cool ist.

EF-Core Antwort nur für das Protokoll

können Sie dieses Problem lösen auch die FluentAPI verwenden. (Ich bevorzuge FluentApi, anstatt meine Modelle mit Attributen zu verunreinigen). Da Sie nicht erwähnt haben, welche EF-Version Sie verwenden, nahm ich an, dass Sie EF Core verwenden.

public class Policy 
{ 
    public int PolicyId { get; set; } 

    public string Description { get; set; } 

    public PayPlan PaymentPlan { get; set; } 
} 

public class PayPlan 
{ 
    public int PayPlanId { get; set; } 
    public string Description { get; set; } 

    public Policy Policy { get; set; } 
    public int? PolicyId { get; set; } 
} 

Kontextklasse:

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Policy>() 
     .HasOne(a => a.PaymentPlan) 
     .WithOne(b => b.Policy) 
     .IsRequired(false) 
     .HasForeignKey<PayPlan>(b => b.PolicyId) 
     .OnDelete(DeleteBehavior.Cascade); 
} 

Dies wird in den folgenden Tabellen auf SQL erzeugen:

enter image description here

+0

Ich bin auf EF 6. Ich ging voran und fügte das der ursprünglichen Beschreibung hinzu. Ich werde diesen Vorschlag in einem Moment ausprobieren. –

+0

Beachten Sie, dass ich aktualisiert habe, um die Beziehung optional zu machen. Habe das vergessen. – jpgrassi

+1

@ Goblyn27 überprüfen Sie meine aktualisierte Antwort .. Ich fürchte, es ist keine gute Nachricht = /. – jpgrassi

2

Wenn ich Ihre Anforderungen richtig verstanden habe, wollen Sie Modell so bauen:

public class Policy { 
    [Key] 
    public int PolicyId { get; set; } 
    // this attribute is not required, but I prefer to be specific 
    // this attribute means navigation property PaymentPlan 
    // is "anoter end" of navigation property PayPlan.Policy 
    [InverseProperty("Policy")] 
    public virtual PayPlan PaymentPlan { get; set; } 
} 

public class PayPlan { 
    [Key] 
    public int PayPlanId { get; set; } 
    // define foreign key explicitly here 
    [ForeignKey("Policy")] 
    public int PolicyId { get; set; } 

    public virtual Policy Policy { get; set; } 

    public string Description { get; set; } 
} 

Update: Die oben genannten Arbeiten in EF-Core, aber funktioniert nicht in EF 6. EF 6 behandelt dies als eine zu viele Beziehung (und stimmt darin, weil eine Richtlinie mehrere PayPlans haben könnte). Um eine zu (null oder) eine Beziehung zu erstellen, können Sie Modell wie folgt zu erstellen:

public class Policy 
{ 
    [Key] 
    public int PolicyId { get; set; }     
    [InverseProperty("Policy")] 
    public virtual PayPlan PaymentPlan { get; set; } 
} 

public class PayPlan 
{ 
    [Key, ForeignKey("Policy")] 
    public int PolicyId { get; set; }   

    public Policy Policy { get; set; } 

    public string Description { get; set; } 
} 

So hat Payplan nicht seine eigene ID haben und stattdessen hat policyId die beide PK und FK ist. Auf diese Weise kann nur ein (oder keiner) Tarif für eine Richtlinie vorhanden sein.

+0

Ja, das habe ich gerade eben versucht. Die Fehlermeldung war ein Geist-f ** k. "PayPlan_Policy_Source: Multiplizität ist in der Rolle 'PayPlan_Policy-Source' in der Beziehung 'PayPlan_Policy' nicht gültig. Da die Eigenschaften der abhängigen Rolle nicht die Schlüsseleigenschaften sind, muss die Obergrenze der Multiplizierung der abhängigen Rolle '*'" –

+1

Ja Sie sind richtig. Ich habe dieses Modell mit EF Core getestet, bei dem das so funktioniert, wie Sie es erwarten, aber in EF 6 wirft es tatsächlich den von Ihnen geposteten Fehler. – Evk

Verwandte Themen