Laden...

EF Core 3.1 verliert den FK Wert beim hinzufügen der Daten

Erstellt von Duesmannr vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.242 Views
D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 4 Jahren
EF Core 3.1 verliert den FK Wert beim hinzufügen der Daten

Hallo, ich mal wieder..

Asp.Net Core 3.1 und EF Core 3.1

Ich habe derzeit ein kleines Problem mit meinen FK's.

Eine User Entity hat die Properties:


public Guid? CreatedById { get; set; }

public Guid? ModifiedById { get; set; }

public User CreatedBy { get; set; }

public User ModifiedBy { get; set; }

Relation und Index die ich erstelle:


builder.HasOne(b => b.CreatedBy)
    .WithOne()
    .HasForeignKey<TEntity>(b => b.CreatedById)
    .OnDelete(DeleteBehavior.Restrict);

builder.HasOne(b => b.ModifiedBy)
    .WithOne()
    .HasForeignKey<TEntity>(b => b.ModifiedById)
    .OnDelete(DeleteBehavior.Restrict);

builder.HasIndex(b => b.CreatedById)
    .IsUnique(false);

builder.HasIndex(b => b.ModifiedById)
    .IsUnique(false);

Datenbank passt auch soweit.

Ich füge dann zwei neue User hinzu:


using IServiceScope serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope();
ApplicationDbContext context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

context.Database.Migrate();

User systemUser = context.Users.FirstOrDefault(x => x.FirstName.Equals("System"));

User rd = new User
{
    Email = "*",
    CreatedById = systemUser.Id,
    ModifiedById = systemUser.Id
};

User ab = new User
{
    Email = "*",
    CreatedById = systemUser.Id,
    ModifiedById = systemUser.Id
};

context.Add(rd);
context.Add(ab);
context.SaveChanges();

Werden auch beide mit in die DB übernommen. Nur verliert rd immer den FK zu "SystemUser" und ab behält ihn.
SQL Profiler mal nachgesehen ob was nicht stimmt, aber die Datenbank bekommt den FK schon gar nicht.

In den Dokus und auch im Netz finde ich nichts dazu.
Es hat ja irgendwas mit dem SystemUser zu tun, aber was genau, keine Ahnung.

Idee woran es liegt?

Grüße
duesmannr

16.835 Beiträge seit 2008
vor 4 Jahren

Hi,

nur ein gut gemeinter Rat, auch damit Du mehr Freude am Code hast und schneller voran kommst: Du solltest Dir echt mal 1-2 Stunden Zeit nehmen und einfach mal die Dokumentationen grob überfliegen.

Du machst hier (wie auch in den anderen Thread zu sehen) immer wieder "Leichtsinnsfehler" bzw. "Konzeptfehler", weil Du offenbar einfach drauf los legst.
Das kann Dir ja auch kein Spaß machen, oder? 😉

  1. Navigation Properties sollte man (außer Du hast technische Anforderungen) mit virtual deklarieren.
  2. .IsUnique(false) ist quatsch, weil das sowieso schon implizit der Fall ist. Ein Index auf FKs macht aber meistens sinn; das passt.
  3. Wenn Du schon die vollständige Entität geladen hast, dann ist die EF Empfehlung auch die Navigation für die Zuweisung zu nutzen und nicht nur die FK-Eigenschaft (was hier aber am Fehler nichts ändert); Navigation always wins.

SQL Profiler mal nachgesehen ob was nicht stimmt, aber die Datenbank bekommt den FK schon gar nicht.

Im EF Core Log sollte der Fehler zu sehen sein; das ist prinzipiell auch der richtige Ort dafür.

Es hat ja irgendwas mit dem SystemUser zu tun, aber was genau, keine Ahnung.

Eher nicht.

Du hast im Schema eine 1:1 (HasOne-WithOne) Beziehung konfiguriert; programmierst aber eine 1:n Beziehung.

PS: "Systemuser" ist auch eher so ein Konzept von 1980.
Ist das wirklich eine Anforderung, oder ist Dir da "nichts besseres" eingefallen? Da sollte sich eigentlich immer ne bessere Lösung finden lassen.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 4 Jahren

Danke für deine schnelle Antwort.

nur ein gut gemeinter Rat, auch damit Du mehr Freude am Code hast und schneller voran kommst: Du solltest Dir echt mal 1-2 Stunden Zeit nehmen und einfach mal die Dokumentationen grob überfliegen.

Bevor ich hier was poste, lese ich die entsprechenden Stellen in der Doku immer und immer wieder. Das hier ist nur der letzte Ausweg, was in der letzten Zeit doch relativ häufig ist.

Das kann Dir ja auch kein Spaß machen, oder? 😉

Es hält sich in Grenzen..

  1. .IsUnique(false) ist quatsch, weil das sowieso schon implizit der Fall ist. Ein Index auf FKs macht aber meistens sinn; das passt.

Lasse ich den Aufruf explizit weg, erstellt der EF Core unique Indizes. Und ich erhalte dadurch duplicate entry exceptions.

  1. Wenn Du schon die vollständige Entität geladen hast, dann ist die EF Empfehlung auch die Navigation für die Zuweisung zu nutzen und nicht nur die FK-Eigenschaft (was hier aber am Fehler nichts ändert); Navigation always wins.

Das war nur zu Testzwecken. IdR setze ich immer die Navigation Property.

Du hast im Schema eine 1:1 (HasOne-WithOne) Beziehung konfiguriert; programmierst aber eine 1:n Beziehung.

Ich bin so oft durch mein Datenbank Konzept gegangen und habe das übersehen. Nachdem ich das nun geändert habe, funktioniert es auch.

PS: "Systemuser" ist auch eher so ein Konzept von 1980.
Ist das wirklich eine Anforderung, oder ist Dir da "nichts besseres" eingefallen? Da sollte sich eigentlich immer ne bessere Lösung finden lassen.

Da fällt mir derzeit nichts besseres ein. Da ich CreatedBy und ModifiedBy nie null haben will und es auch eine History Tabelle existiert, brauche ich einen User der die Einträge erstellt hat.

PS: Ich hätte auch eine kurze Frage beim Problem von der Erstellung einer Migration. Bzw. ist das Problem der Code, der daraus entsteht. Ich will dafür nicht einen neuen Thread aufmachen. Und die Doku hilft auch nicht^^

16.835 Beiträge seit 2008
vor 4 Jahren

Da fällt mir derzeit nichts besseres ein. Da ich CreatedBy und ModifiedBy nie null haben will und es auch eine History Tabelle existiert, brauche ich einen User der die Einträge erstellt hat.

Du hast aber schon gesehen, dass der Systemuser Dir hier nicht hilft?
Denn der Systemuser hat dann halt CreatedById null.

Du kommst hier um ein Nullable nicht drum herum. Du verlagerst also nur jedoch löst Dein "Problem" nicht.

Laut DSGVO musst Du das Löschen von Daten gewährleisten (jedenfalls gehe ich mal davon aus, dass das hier zutrifft). Technisch gesehen reicht dazu prinzipiell eine Anonymisierung, da das Gesetz nicht von "Datenbankeinträgen löschen" spricht - die Erfahrung zeigt, dass jedoch genau das einfacher ist.
Daher kann es allein vom Prozess dazu kommen, dass CreatedId null sein kann, weil der Benutzer, der jemanden angelegt hat, gelöscht wurde.
Wahrscheinlich machst Du Dir damit also das Leben schwerer.

Wenn das Problem hier dazu gehört, dann kannst Du ruhig mehrere Fragen stellen.
Sinn der Forenregel ist nur, dass so ein Thread kein Endlosthema wird.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 4 Jahren

Du kommst hier um ein Nullable nicht drum herum. Du verlagerst also nur jedoch löst Dein "Problem" nicht.

Kann ich dir nur zustimmen.

Wenn das Problem hier dazu gehört, dann kannst Du ruhig mehrere Fragen stellen.
Sinn der Forenregel ist nur, dass so ein Thread kein Endlosthema wird.

Problem bezieht sich auch größtenteils auf den Thread Titel.

Beim erstellen der DB, Seed ich Daten direkt zur Datenbank und erstelle da auch den "Systemuser". Den ich eventuell komplett rauslasse, aber für zukünftige Probleme gleicher Art hätte ich dann gerne einen Lösungsansatz.

In der OnModelCreating Methode habe ich diese Zeilen


User systemUser = new User
{
    FirstName = "System"
};

modelBuilder.Entity<User>().HasData(systemUser);

List<WorkItemType> workItemTypes = new List<WorkItemType>
{
    new WorkItemType
    {
        Name = "Userstory",
        CreatedById = systemUser.Id,
        ModifiedById = systemUser.Id
    },
    new WorkItemType
    {
        Name = "Task",
        CreatedById = systemUser.Id,
        ModifiedById = systemUser.Id
    },
    new WorkItemType
    {
        Name = "Epic",
        CreatedById = systemUser.Id,
        ModifiedById = systemUser.Id
    },
    new WorkItemType
    {
        Name = "Feature",
        CreatedById = systemUser.Id,
        ModifiedById = systemUser.Id
    },
    new WorkItemType
    {
        Name = "Bug",
        CreatedById = systemUser.Id,
        ModifiedById = systemUser.Id
    },
    new WorkItemType
    {
        Name = "Issue",
        CreatedById = systemUser.Id,
        ModifiedById = systemUser.Id
    }
};

foreach(WorkItemType workItemType in workItemTypes)
{
    modelBuilder.Entity<WorkItemType>().HasData(workItemType);
}

Daraus ensteht die Migration:


migrationBuilder.InsertData(
                schema: "RD",
                table: "Users",
                columns: new[] { "Id", "CreatedById", "ModifiedById", "Firstname" },
                values: new object[] { new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), null, null, "System" });

migrationBuilder.InsertData(
                schema: "RD",
                table: "WorkItemTypes",
                columns: new[] { "Id", "CreatedById", "ModifiedById", "Name" },
                values: new object[,]
                {
                    { new Guid("492ab899-8f7c-4b41-8d14-50d7281374f6"), null, null, "Userstory" },
                    { new Guid("b617a0da-1a45-444c-b13d-85acb0f22164"), null, null, "Task" },
                    { new Guid("1c69cb62-a978-4ef4-96ac-aa1442a100f2"), null, null, "Epic" }
                });

migrationBuilder.InsertData(
                schema: "RD",
                table: "WorkItemTypes",
                columns: new[] { "Id", "CreatedById", "ModifiedById", "Name" },
                values: new object[,]
                {
                    { new Guid("c31dead7-523a-4603-a271-7fde6b5b7d4c"), new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), "Feature" },
                    { new Guid("120908db-e73c-4dac-b980-fb85c3ca98cf"), new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), "Bug" },
                    { new Guid("caec8768-29f1-4831-ae5a-db71ae707dea"), new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), new Guid("9f5f691d-a7d6-49f7-aae6-fdd7281c1339"), "Issue" }
                });

Ich verstehe nicht, warum der einmal drei Datensätze mit null Werten bei CreatedBy und ModifiedBy hat und die restlichen Datensätze mit gefüllten Werten.

16.835 Beiträge seit 2008
vor 4 Jahren

Du hast das HasOne angepasst und die Migration aktualisiert?
Würde nun vermuten: nein 😉

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 4 Jahren

Du hast das HasOne angepasst und die Migration aktualisiert?
Würde nun vermuten: nein 😉

Natürlich nicht. Ist ja auch nicht so, dass man da hätte von alleine drauf kommen können..

Ich danke dir Abt! 😃