Angenommen, ich habe die folgenden Entitäten:
public class Parent
{
public int Id { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
}
Wie lautet die erste fließende API-Syntax des Codes, um zu erzwingen, dass ParentId in der Datenbank mit einer Fremdschlüsseleinschränkung für die Parents-Tabelle erstellt wird, ohne dass eine Navigationseigenschaft erforderlich ist ?
Ich weiß, dass ich Folgendes tun kann, wenn ich eine Navigationseigenschaft Parent to Child hinzufüge:
modelBuilder.Entity<Child>()
.HasRequired<Parent>(c => c.Parent)
.WithMany()
.HasForeignKey(c => c.ParentId);
Aber ich möchte die Navigationseigenschaft in diesem speziellen Fall nicht.
entity-framework
ef-code-first
RationalGeek
quelle
quelle
Antworten:
Mit EF Code First Fluent API ist dies nicht möglich. Sie benötigen immer mindestens eine Navigationseigenschaft, um eine Fremdschlüsseleinschränkung in der Datenbank zu erstellen.
Wenn Sie Code First Migrations verwenden, können Sie der Paketmanagerkonsole (
add-migration SomeNewSchemaName
) eine neue codebasierte Migration hinzufügen . Wenn Sie etwas an Ihrem Modell geändert oder zugeordnet haben, wird eine neue Migration hinzugefügt. Wenn Sie nichts geändert haben, erzwingen Sie eine neue Migration mitadd-migration -IgnoreChanges SomeNewSchemaName
. Die Migration enthält in diesem Fall nur leereUp
undDown
Methoden.Anschließend können Sie die
Up
Methode ändern , indem Sie Folgendes hinzufügen:Wenn Sie diese Migration (
update-database
auf der Paketverwaltungskonsole) ausführen, wird eine ähnliche SQL-Anweisung ausgeführt (für SQL Server):Alternativ können Sie ohne Migrationen einfach einen reinen SQL-Befehl mit ausführen
Dabei
context
handelt es sich um eine Instanz Ihrer abgeleiteten Kontextklasse undsql
nur um den obigen SQL-Befehl als Zeichenfolge.Beachten Sie, dass EF bei alledem keine Ahnung hat, dass
ParentId
es sich um einen Fremdschlüssel handelt, der eine Beziehung beschreibt. EF betrachtet es nur als gewöhnliche Skalareigenschaft. Irgendwie ist all das nur komplizierter und langsamer als das Öffnen eines SQL-Verwaltungstools und das manuelle Hinzufügen der Einschränkung.quelle
[ForeignKey("ParentTableName")]
. Dadurch wird die Eigenschaft mit dem Schlüssel verknüpft, der sich in der übergeordneten Tabelle befindet. Jetzt haben Sie jedoch einen fest codierten Tabellennamen.Obwohl dieser Beitrag
Entity Framework
nichtEntity Framework Core
dazu gedacht ist, kann er für jemanden nützlich sein, der dasselbe mit Entity Framework Core erreichen möchte (ich verwende V1.1.2).Ich habe keine Navigationseigenschaften müssen (obwohl sie sind nett) , weil ich DDD übe und ich möchte
Parent
undChild
zwei separate Aggregate Wurzeln zu sein. Ich möchte, dass sie über Fremdschlüssel und nicht über infrastrukturspezifischeEntity Framework
Navigationseigenschaften miteinander kommunizieren können .Alles, was Sie tun müssen, ist, die Beziehung auf einer Seite mit
HasOne
undWithMany
ohne Angabe der Navigationseigenschaften zu konfigurieren (sie sind schließlich nicht vorhanden).Ich gebe auch Beispiele zum Konfigurieren von Entitätseigenschaften, aber das wichtigste hier ist
HasOne<>
,WithMany()
undHasForeignKey()
.Ich hoffe es hilft.
quelle
HasOne<Parent>()
und.WithMany()
unter der untergeordneten Konfiguration. Sie verweisen überhaupt nicht auf die Navigationseigenschaften, da ohnehin keine Navigationseigenschaften definiert sind. Ich werde versuchen, es mit meinen Updates klarer zu machen.Kleiner Hinweis für diejenigen, die DataAnotations verwenden und die Navigationseigenschaft nicht verfügbar machen möchten - verwenden
protected
Das war's - der Fremdschlüssel mit
cascade:true
AfterAdd-Migration
wird erstellt.quelle
Parent
oder nurParentId
?virtual
Eigenschaften können nicht seinprivate
.Im Fall von EF Core müssen Sie nicht unbedingt eine Navigationseigenschaft angeben. Sie können einfach einen Fremdschlüssel auf einer Seite der Beziehung angeben. Ein einfaches Beispiel mit Fluent API:
quelle
Ich verwende .Net Core 3.1, EntityFramework 3.1.3. Ich habe mich umgesehen und die Lösung, die ich gefunden habe, war die Verwendung der generischen Version von
HasForeginKey<DependantEntityType>(e => e.ForeginKeyProperty)
. Sie können eine Eins-zu-Eins-Beziehung wie folgt erstellen:Ich hoffe, dies hilft oder liefert zumindest einige andere Ideen zur Verwendung der
HasForeginKey
Methode.quelle
Mein Grund dafür nicht Navigationseigenschaften verwende, sind Klassenabhängigkeiten. Ich habe meine Modelle in wenige Baugruppen unterteilt, die in verschiedenen Kombinationen in verschiedenen Projekten verwendet werden können oder nicht. Wenn ich also eine Entität habe, die über eine Nagivationseigenschaft verfügt, die von einer anderen Assembly klassifiziert werden soll, muss ich auf diese Assembly verweisen, die ich vermeiden möchte (oder jedes Projekt, das einen Teil dieses vollständigen Datenmodells verwendet, enthält alles).
Und ich habe eine separate Migrations-App, die für Migrationen (ich verwende Automigrationen) und die anfängliche DB-Erstellung verwendet wird. Dieses Projekt bezieht sich aus offensichtlichen Gründen auf alles.
Lösung ist C-Stil:
alt
Schlüssel in VS)#if _MIGRATION
Contact
im Beispiel nicht auf Assembly mit Klasse verweisen ).Stichprobe:
Natürlich sollten Sie die
using
Direktive auf die gleiche Weise deaktivieren und den Namespace ändern.Danach können alle Konsumenten diese Eigenschaft wie gewohnt als DB-Feld verwenden (und nicht auf zusätzliche Assemblys verweisen, wenn sie nicht benötigt werden), aber der DB-Server weiß, dass es sich um FK handelt, und kann Kaskadierung verwenden. Sehr schmutzige Lösung. Funktioniert aber.
quelle