Laden...

LookUp mit EF core 6

Erstellt von bigeddie vor einem Jahr Letzter Beitrag vor einem Jahr 859 Views
B
bigeddie Themenstarter:in
372 Beiträge seit 2007
vor einem Jahr
LookUp mit EF core 6

Verwendetes Datenbanksystem: SQL-Server 2019 express & EF core 6

Hallo Gemeinde,

ich habe folgende 2 Klassen definiert:


public class Gender
{
    public int Id { get; set; }
    public string Text { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string Vorname { get; set; }
    public string Nachname { get; set; }
    public Gender Gender { get; set; }
}

Gender soll die Werte

  • männlich
  • weiblich
  • divers

enthalten und die Configuration läuft über


public class GenderConfiguration : IEntityTypeConfiguration<Gender>
{
    public void Configure(EntityTypeBuilder<Gender> builder)
    {
        builder.HasKey(g=>g.Id);
        builder.Property(p => p.Text).HasMaxLength(80);
    }
}

public void Configure(EntityTypeBuilder<Person> builder)
{
       builder.HasKey(x => x.Id);
       builder.Property(p => p.Vorname).HasMaxLength(80).IsRequired(false);
      builder.Property(p => p.Nachname).HasMaxLength(80).IsRequired(false);
}


Die Migration sieht wie folgt aus:


         protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Genders",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Text = table.Column<string>(type: "nvarchar(80)", maxLength: 80, nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Genders", x => x.Id);
                });

            migrationBuilder.CreateTable(
                name: "Persons",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Vorname = table.Column<string>(type: "nvarchar(80)", maxLength: 80, nullable: true),
                    Nachname = table.Column<string>(type: "nvarchar(80)", maxLength: 80, nullable: true),
                    GenderId = table.Column<int>(type: "int", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Persons", x => x.Id);
                    table.ForeignKey(
                        name: "FK_Persons_Genders_GenderId",
                        column: x => x.GenderId,
                        principalTable: "Genders",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateIndex(
                name: "IX_Persons_GenderId",
                table: "Persons",
                column: "GenderId");
        }

Die Zeile


GenderId = table.Column<int>(type: "int", nullable: false)

verwirrt mich jedoch etwas, denn

  • warum ist die Column nicht nullable?
  • wie muss ich das Feld in der Configuration bearbeiten um sie nullable zu bekommen?
  • wie kann ich der Spalte einen DEFAULT-Wert zuweisen?

Viele Grüße

Bigeddie

Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉

16.842 Beiträge seit 2008
vor einem Jahr

warum ist die Column nicht nullable?

Weil Du die Relation nicht als Nullable deklariert hast.


public Gender Gender { get; set; }

// Nullable wäre
public Gender? Gender { get; set; }

Des weiteren wäre ein Relationssetup mit einem FK empfohlen.
Nicht immer notwendig, ist jedoch empfohlen.



public Gender? Gender { get; set; }
public int? GenderId { get; set; }

// dazu die Relationsconfig

wie kann ich der Spalte einen DEFAULT-Wert zuweisen?

Es ist keine Spalte, sondern eine Relation. Der kannst Du nicht relationsfrei einen Default Wert geben.
Wäre ja in der Schemadefinition so, dass Du eine Entity Id vergeben würdest, die zum Zeitpunkt des Deployments gar nicht existiert -> Möglich, jedoch Fehlerpotential riesig.

Üblicher ist ohnehin eine Implementierung mit einem Enum.


public enum GenderType
{ 
  Unknown = 0,
  Male = 1,
  Female = 2,
  Diverse = 3
  // Beliebig Erweiterbar
}

public GenderType GenderType { get; set; }

Damit wäre Gender weiterhin pflicht, durch Unknown = 0 kannst Du aber sehr einfach einen Defaultwert ( 0 ) verwenden.
Sowohl automatisch (durch die Entity Confguration) wie auch per Code.

Aber ja: das heisst jedoch erweiterbar nur per Code.
Wäre bei einem GenderEntity vorgehen auch anders, aber es muss eine definierte Relation existieren, damit etwas Default werden kann.
Ist aber keine EF Einschränkung, sondern einfach wie SQL Relationen funktionieren.
Mach halt ansonsten nullable jedoch ohne default Wert. Null = "Unknown" aka "keine Angabe".

PS: Dein Naming passt nicht ganz.
Empfohlen ist Entitätsmodellen auch den Entitätssuffix "Entity" zu geben -> GenderEntity.
Es sind schließlich spezifische Datenmodelle, die nicht vermischt werden sollen.

B
bigeddie Themenstarter:in
372 Beiträge seit 2007
vor einem Jahr

Hallo Abt,

erstmal vielen Dank für die Infos, hat mir sehr weitergeholfen.

Von welchen Bedingungen hängt es eigentlich ab, ob ich ein Relationssetup verwenden "muss" oder nicht?
Oder sollte ich dies durch die Migrations kontinuierlich überprüfen?

Vielen Dank und viele Grüße

Bigeddie

Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉

16.842 Beiträge seit 2008
vor einem Jahr

Von welchen Bedingungen hängt es eigentlich ab, ob ich ein Relationssetup verwenden "muss" oder nicht?

Die automatischen Relationen basieren auf Referenzen und (Namens)konventionen.
Es ist durchaus "viel" Black Magic dahinter. Wenn man das System im Hintergrund nicht versteht bzw nicht kennt, dann kann es ganz einfach zu Problemen führen, die man aufgrund des Informationsmangels nicht nachvollziehen kann.
Gerade Einsteiger tun sich also viel einfacher wenn sie bewusst mit Relationen arbeiten.

Meine generelle Empfehlung: ausnahmslos immer selbst die Relationen verantworten.
Senkt enorm das Fehlerpotential.

Ansonsten gibts auch programmatische Vorteile, die man nutzen kann, wenn man zB mit manuell angelegten FK-Eigenschaften arbeiten, einfach weil man sich SQL Queries spart.
Die Best Practise im generellen DB Umgang ist: nur die Daten zu laden, die man laden muss.
Eine ganze Enität zu laden ist verhältnismäßig teuer und daher durchaus ein Performance Faktor.

Das Forum hier verwendet auch komplett EF Core und wir arbeiten nur in ganz ganz seltenen Fällen (meistens beim Schreiben) überhaupt mit Entitäts-Modellen.
>90% des Codes sind Projektionen, also nur Teildaten: bessere Performance.

Letzteres lohnt sich vor allem für größere Anwendungen, weniger für "Mini Tools".

Ansonsten halt: auch wenn EF das gerne so vermarktet, dass die Entitäts-Modelle auch "Business Modelle" sein können: Nein.
Das mag vielleicht in einer kleinen Welt mit viel Willen funktionieren, aber eigentlich sehen in ~100% der Fälle eine Datenstruktur einfach anders aus als logische Modelle.
Ist also ganz einfach auch eine Sache der Architektur, dass diese "Marketing Aussage" aller ORM so nicht funktionieren kann.

B
bigeddie Themenstarter:in
372 Beiträge seit 2007
vor einem Jahr

Hallo Abt,

danke, dass du dir die Mühe mit der sehr ausführlichen Antwort gemacht hast!

Gibt es für die Definition der Relations (ohne die Nutzung der "Black Magic" Quellen über welche man sich das Wissen aneignen kann (fluent API)?
Habe nur die Doku bei MS gefunden und irgend welche mash-up Seiten die sich auf alle möglichen Versionen von EF beziehen ohne direkt auf die letzte Version von EF (core) einzugehen.

Vielen Dank

Bigeddie

Man muß nichts wissen,
man muß nur wissen wer es wissen könnte
oder wo es steht😉

16.842 Beiträge seit 2008
vor einem Jahr

Gibt es für die Definition der Relations (ohne die Nutzung der "Black Magic" Quellen über welche man sich das Wissen aneignen kann?
..
Habe nur die Doku bei MS gefunden und irgend welche mash-up Seiten die sich auf alle möglichen Versionen von EF beziehen ohne direkt auf die letzte Version von EF (core) einzugehen.

Kann eigentlich nicht sein.

Seit Beginn von EF werden die Docs parallel zu den Versionen gepflegt - ich mach da auch mit, daher weiß ich das.
Nicht alle Docs sind perfekt, auch EF hält sich teilweise nicht an (ihre eigenen/Community) Empfehlungen, aber man muss auch sagen, dass viele Leute Docs falsch bedienen.
Docs sind dazu da Themen zu behandeln, Konzepte aufzuzeigen und einzelne Punkte zu erklären; man kann nicht immer "das Große und Ganze" zeigen, das man dann Copy-Paste übernehmen kann.
Das ist nicht der Sinn von Docs, egal ob EF Core, Dapper, Java Spring, NodeJS und Co.
Leider existiert doch oft genau eine solche Erwartungshaltung, die natürlich nicht erfüllt wird.

Die EF Docs sind in ihrer Sache sehr ausführlich; Beispiele jedoch abstrakt und nicht Realitätsnah. Man muss noch selbst nachdenken, das stimmt.
Overview of Entity Framework Core - EF Core
Das ist übrigens der erste Treffer der Google Suche nach "EF core docs"

Das sagt aber EF Core auch wiederholt an vielen Stellen, Beispiel:

Most of the samples in this article use a one-to-many relationship to demonstrate concepts. Relationships - EF Core

Auf gleichen Seite werden - für die aktuelle Version - auch die Konventionen erklärt.
Relationships - EF Core - Conventions

While it is recommended to have a foreign key property defined in the dependent entity class, it is not required. Relationships - EF Core - No FK

Die Docs gibts also doch, hast eher nicht so recht geschaut 🙂