Entity Framework (Core) - Wie verifiziert man am effektivsten, ob ein Benutzer ein Entity aktualisieren darf?

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von VincentTB.

    Entity Framework (Core) - Wie verifiziert man am effektivsten, ob ein Benutzer ein Entity aktualisieren darf?

    Hi,
    ich versuche mich gerade an einem etwas größeren Projekt, in welchem verschiedene Benutzer verschiedene Projekte anlegen können, welche verschiedene verlinkte Tabellen haben. Das ganze wird von eine REST-Api betrieben, also es wird jedes Mal ein neuer DbContext erstellt (die Entries werden nicht getrackt).

    Jetzt wäre meine Frage, wie man es am besten macht, eine ungetrackte Entity zu aktualisieren und gleichzeitig zu gewährleisten, dass die Entity auch dem Benutzer gehört. Ich weiß vorher, dass das Projekt xyz dem Benutzer gehört und eigentlich sollte auch die aktualisierte Entity dem Benutzer gehören, aber ich muss ja trotzdem die ID überprüfen, sonst könnte der Benutzer ja jede Entity aktualisieren. In MySQL würde ich jetzt so eine Query erstellen:

    SQL-Abfrage

    1. ​UPDATE dependentEntity INNER JOIN project SET dependentEntity.property = 12 WHERE project.ProjectId = 19 AND dependentEntity.id = 12

    Es wird überprüft, ob das Projekt zu der Entity gehört und nur dann die Entity aktualisiert. Das ist eine schöne Query, die alles wichtige beinhaltet und relativ gut performen sollte.

    In EF Core würde ich jetzt sowas hier machen:

    C#-Quellcode

    1. ​var context = new MyDbContext();
    2. var entity = _context.Projects.First(x => x.ProjectId = 19).DepdendentEntities.First(x => x.id = 12);
    3. //hier gibt es einen Fehler, wenn die Entity nicht in dem Projekt gefunden wurde
    4. entity.property = 12;
    5. context.SaveChanges();

    Aber das führt ja zwei Befehle aus, einmal den SELECT Befehl und dann nochmal den UPDATE Befehl in SaveChanges();. Kann man das irgendwie verbessern oder muss man das hier in Kauf nehmen für den Comfort? (oder macht man hier einfach die SQL Abfrage mit dem EF?)
    Mfg
    Vincent

    Hallo

    Wenn ich dein vorhaben richtig verstanden habe wird an dein REST eine Entität geschickt von welcher du weist das diese geändert wurde und du willst nun ein Update ohne einem Select machen. Erstmal solltest du prüfen ob die Entität wirklich nur geändert wurde. z.b. anhand der ID.

    Du kannst jederzeit eine Entität dem ChangeTracker mit Attach hinzufügen und den EntityState auf Changed setzen.

    VB.NET-Quellcode

    1. context.Attach(deineEntität)
    2. context.Entity(deineEntität).State = EntityState.Modified



    Zu beachten das du das Tracking aber für dieses Vorhaben auch einschaltest.
    Natürlich kann man dies jetzt noch verfeinern da in diesem Fall EF davon ausgeht das sich die ganze Entität geändert hat anstatt vielleicht nur ein Propertie, aber da kannst du ja noch rumspielen.

    Edit: Wenn du nur bestimmte Properties aktualisieren möchtest dann z.b. mit context.Entry(deineEntität).Property(function(x) x.Property).IsModified = True.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nofear23m“ ()

    Hey,
    erstmal dank für deine Antwort.
    Mein Problem ist jetzt, dass ich doch irgendwie überprüfen muss, ob der Benutzer die entity überhaupt aktualisieren darf bzw. die entity zu einem Projekt des Benutzers gehört.
    Mfg
    Vincent

    Hallo

    Naja, entweder du bekommst die Info über deine REST API mit oder dir bleibt nichts über als zu prüfen.
    Da du ja immer einen neuen context öffnest (oder öffnen must) hast du die Info ja nicht. hier reden wir aber von einem Roundtrip der ein paar Millisekunden benötigt.
    Übrigens würde ich dir die Performantere prüfung mit Any empfehlen:

    VB.NET-Quellcode

    1. Dim CanEdit as Boolen = _context.Projects.First(Function(p) p.ProjectId = 19).DepdendentEntities.First(function(d) d.id = 12).Any
    2. If canedit then ....


    Da reden wir local vermutlich über 10 Millisekunden.
    Oder du gibst die Info eben an den Client weiter und beim "speichern" über deine REST wieder mit. Ist aber vermutlich weniger performant da hier die WAN Leitung mehr bemüht wird.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Mein Problem ist halt, dass es ja von SQL her in einer einzigen query geht.

    Oder du gibst die Info eben an den Client weiter und beim "speichern" über deine REST wieder mit.

    Dann über ein JWT? Weil ich muss ja irgendwie gucken, dass der Client nicht lügt.
    Mfg
    Vincent

    Hallo

    Es ist eben ein OR Mapper. Da muss man abstriche machen. Dafür wird eben eine vielzahl an Datenbanken unterstützt. Da kann EF schwer auf DB Spezifische Funktionen eingehen.

    Was du machen kannst: Du kannst einen SQL absetzen. Ich bin jetzt vor keinem Rechner und weis das Schlüsselwort nicht genau. IRGENDWAS wie SQLcommand.

    Anders als das EF 6 kann EF Core sogar die Rückgabe vom Server in eine Entität wandel.

    Wenn du willst kann ich dir genauere Infos geben wenn ich wieder vor einem Rechner sitze.

    Bedenke aber das du dann aber nicht mehr einfach eine andere DB verwenden kannst ohne den Code umzuschreiben.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Ah, okay, danke für deine Antwort. Eine eigene SQL Abfrage wäre dann auch meine Alternative gewesen. Dann mache ich das erstmal mit dem entity framework Weg und wenn das Performance Probleme macht, muss ich das halt anpassen.
    Mfg
    Vincent