EntityFramework: CodeFirst vs. ModelFirst

  • WPF

Es gibt 55 Antworten in diesem Thema. Der letzte Beitrag () ist von Mono.

    Besten Dank @MrTrebron.

    Jetzt sind hoffentlich alle Glücklich. Brauch nur noch schreiberechte für Push. Bekommst ne PN.

    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. ##

    @ErfinderDesRades, ist das so in Ordnung für dich?
    Denke das ist jetzt in deinem Interesse, ich werde nun das TFS Projekt Offline schalten.

    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. ##

    Jo, ich habs ans laufen gekriegt, und ich kann auch nachträglich ein edmx-Model davon generieren - weisst ja: Ich verstehe ein Datenmodell am besten, wenn ich's als ER-Diagramm vorliegen hab.
    Darüberhinaus wäre das mit dem generierten edmx-Model auch eine Art "Database.First" - wovon MrTrebon gesprochen hat.
    Weil wenn wirklich mehrere Anwendungen aus derselben DB entstehen sollen, so wird nur eine von denen die Db mittels CodeFirst gestalten können - die anderen müssen entweder das CodeFirst-Modell komplett übernehmen, oder sich mittels DatabaseFirst ein eigens angemessenes Model generieren.
    Es scheint aber auch ein DatabaseFirst für CodeFirst zu geben, also ohne edmx. Habich aber nicht probiert.

    Übrigens, dass ModelFirst ausstirbt, davon bin ich nicht überzeugt. Imo gut möglich, dass MS dieses Feature demnächst nachliefert.

    Aber ich will ModelFirst garnimmer verteidigen. CodeFirst ist ebensogut, und statt T4 Templates kann man sich ja auch Snippets anlegen, wenn man partout kein Bock auf BoilerPlate-Code-Selberschreiben hat.
    Bei meine ModelFirst-Experimente (funzt das jetzt eiglich bei dir?) konnte ich (glaub) Löschweitergabe in der Db konfigurieren - das hat dein CodeFirst (noch) nicht.
    Ich nehme aber an, dasses dafür vorgesehene Attribute gibt bei CodeFirst, odr?
    OK, ich gehe es der Reihe nach durch. Puh

    ErfinderDesRades schrieb:

    Darüberhinaus wäre das mit dem generierten edmx-Model auch eine Art "Database.First" - wovon MrTrebon gesprochen hat.

    Nicht ganz. Wenn du DataBaseFirst machst wir einmahlig (!!) ein Model generiert. Dieses Model ist dann Stand der Dinge. Änderst du die DB musst du völlig Manuell das ganze Model wieder generieren mit dem Assistenten. Das kann dir aber auch viel zerstören.

    ErfinderDesRades schrieb:

    Weil wenn wirklich mehrere Anwendungen aus derselben DB entstehen sollen, so wird nur eine von denen die Db mittels CodeFirst gestalten können - die anderen müssen entweder das CodeFirst-Modell komplett übernehmen, oder sich mittels DatabaseFirst ein eigens angemessenes Model generieren.

    Also das mit den Models und EF ist so eine Sache. Ob du jetzt DBfirst oder ModelFirst oder CodeFist hast ist im Grunde egal.
    Beispiel: Hast du CodeFirst und dein Model stimmt genau mit dem Model einer DB überein kann dieses verwendet werden. EF erkennt das die DB mit dem Model übereinstimmt und kann Arbeiten.
    Du kannst also theoretisch (!!) alle drei Ansätze in drei verschiedenen Apps haben und die kommen sich nicht in die Quere. Theoretisch, ich habs noch nciht probiert, aber es sollte möchlich sein.

    ErfinderDesRades schrieb:

    Es scheint aber auch ein DatabaseFirst für CodeFirst zu geben, also ohne edmx. Habich aber nicht probiert.

    Wie oben beschrieben bitte Vorsicht, sind verschiedene Ansätze. Es gibt nicht DatabaseFirst für CodeFirst. Es gibt über die PowerTools die möglichkeit 1x das Model (Code) anhand der DB Struktur zu generieren. Es ist und bleibt dann aber dennoch CodeFirst. Wie gesagt es wird dann nur einmahlig der Code generiert und ab da geht es mit Code weiter und über die Migrations (habe ich auch implementiert) werden dann Modeländerungen in die DB übertragen.

    ErfinderDesRades schrieb:

    Übrigens, dass ModelFirst ausstirbt, davon bin ich nicht überzeugt. Imo gut möglich, dass MS dieses Feature demnächst nachliefert.

    Vieleicht, auf der EF Core Roadmap steht es definitiv nicht oben und MS sowie die Entwickler von EF Core haben mehrmals definitiv gesagt das es nicht kommen wird. Frag doch mal hier und GitHub nach (EF ist ja OpenSource).
    Oder du guckst in der Roadmap nach, da ist auch nix drinnen. Sie legen mehr Wert darauf das EF Core Plattformunabhängig ist und mehr DB Provider unterstützen soll.
    Aber (!!) sie haben sich dazu hinreißen lassen das es ein UpdateFrom Database über Commands zur Entwicklungszeit geben wird. Siehe hier.

    ErfinderDesRades schrieb:

    Bei meine ModelFirst-Experimente (funzt das jetzt eiglich bei dir?) konnte ich (glaub) Löschweitergabe in der Db konfigurieren - das hat dein CodeFirst (noch) nicht.
    Ich nehme aber an, dasses dafür vorgesehene Attribute gibt bei CodeFirst, odr?

    Stimmt, hat emines nicht, weil es meines nicht benötigt, jede meiner Klassen implementiert das ILogicalDelete Interface und kann somit NUR als gelöscht markiert werden da diese Implementierung das verlangt !!!
    Geht bei CodeFirst über die FluentApi. Hier ein Beispiel aus der Doku derweil:

    VB.NET-Quellcode

    1. modelBuilder.Entity(Of Course).HasRequired(Function(t) t.Department).WithMany(Function(t) t.Courses).HasForeignKey(Function(d) d.DepartmentId).WillCascadeOnDelete(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. ##

    Hi Nofear23m!
    Ich habe mir mal deine SaveChanges() Function angeschaut und habe eine Frage dazu.
    Du schreibst:

    C#-Quellcode

    1. Dim objectStateEntries = ChangeTracker.Entries().Where(Function(e) TypeOf e.Entity Is ModelBase AndAlso e.State <> EntityState.Detached AndAlso e.State <> EntityState.Unchanged).ToList()

    Aber im Select Case​ fragst du nur nach hinzugefügt, gelöscht und geändert ab.
    Dann müßte doch:

    C#-Quellcode

    1. Dim objectStateEntries = ChangeTracker.Entries().Where(Function(e) TypeOf e.Entity Is ModelBase
    2. ).ToList()

    ​total ausreichen.
    ​Warum benutzt du "Detached" und "Unchanged" ? Das versteh ich nicht.
    Gruß Helge
    Hallo @hlghyr

    hlghyr schrieb:

    ​Warum benutzt du "Detached" und "Unchanged" ? Das versteh ich nicht.

    Im Grunde einfach um weniger Ergebnisse zurück zu bekommen. Wenn ich es mache wie du beschrieben hast bekomme ich Ergebnisse zurück welche ich ja gar nicht benötige.

    Wie du richtig sagst frage ich im Select Case nur Added, Deleted, und Modified ab. Also benötige ich auch nur diese Entitäten. Wozu also alle Abrufen?
    Ist jetzt nicht sooo wichtig für die Performance aber warum soll ich ZU viel laden, so habe ich es auch z.b. beim Debuggen leichter.

    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. ##

    Also ich beschäftige mich auch seit einer Weile mit EF6 da ich vorher in Python mit einem ORM gearbeitet habe (von DJango) und es mir sehr gut gefallen hat.
    Dort hat man generell Codefirst, allerdings mit mehr Möglichkeiten die Models zu designen.

    Bei CodeFirst in EF fehlen mir richtige Relationen mit Cascade Optionen, die muss man alle selber reinprogrammieren. (Also die Cascade on Delete/Update usw).
    Bei ModelFirst kann man die Erstellen weil daraus ein SQL Script generiert wird für die Datenbank die das dann SQL seitig einrichtet.
    Allerdings hat man bei ModelFirst das Problem das Migrations nicht gut unterstützt werden. Das heißt wenn man mal Daten hat und sein Model erweitert hat man hier Probleme, da man sich selber Scripts schreiben muss (oder gibts da ieine Extension für). Bei Codefirst gibt es wohl vernünftige Migrationsmöglichkeiten schon von Haus aus mit so einem Migration Tool. In der Doku von MS wird auch explizit erwähnt das dies für ModelFirst aktuell nicht funkioniert und auch nicht erwähnt das dies geplant ist.

    Da ich ähnlich wie @ErfinderDesRades auch das Model mir gerne anschaue und auch um zu sehen was alles möglich ist bei EF habe ich auch mit ModelFirst begonnen, dann die generierten Klassen einfach nur kopiert und die Templates usw wieder rausgehauen und auf CodeFirst umgestellt. (So habe ich mir gespart den Code für die Entities noch mal zu schreiben).

    Letztlich scheint mir CodeFirst deutlich flexibler zu sein auch wenn es (aktuell) etwas aufwändiger ist und ich gehe davon aus das sich das auf lange Sicht auch durchsetzt.
    Das ist meine Signatur und sie wird wunderbar sein!
    ich denke auch, dass

    VB.NET-Quellcode

    1. ChangeTracker.Entries().Where(Function(e) TypeOf e.Entity Is ModelBase
    oder gar

    VB.NET-Quellcode

    1. ChangeTracker.Entries()
    dieselbe Ergebnismenge liefert wie

    VB.NET-Quellcode

    1. ChangeTracker.Entries().Where(Function(e) TypeOf e.Entity Is ModelBase AndAlso e.State <> EntityState.Detached AndAlso e.State <> EntityState.Unchanged)
    Weil Unchanged wird ein ChangeTracker doch eh nicht liefern, oder?
    Und andere Operationen als Update, Insert werden doch eh nicht ausgeführt.
    Ich würde im Select aber einen Else-Zweig einführen, mit dem detectiert wird, ob was schief gelaufen ist.

    Nofear23m schrieb:

    Wie du richtig sagst frage ich im Select Case nur Added, Deleted, und Modified ab. [...benötige...]
    Hmm - Deleted benötigst du doch garnet - deine Persistenz-Strategie sieht (laut ModelBase.vb) ja vor, zu löschendes nicht zu löschen, sondern nur als "gelöscht" zu markieren.
    Hi @Nofear23m!
    Ok! So leuchtet es mir zum Teil ein. Doch das "Unchanged" mit der Beschreibung : "Die Entität wird vom Kontext nachverfolgt und ist in der Datenbank vorhanden. Ihre Eigenschaftswerte unterscheiden sich nicht von den Werten in der Datenbank." widerspricht dem doch. Sorry! Vielleicht hab ich bloß ein Denkfehler. Ansonsten finde ich aber gut was du geschrieben hast und werde es bestimmt auch benutzen.
    Gruß Helge
    Wie gesagt: Eine ungefilterte Abfrage sollte dasselbe Ergebnis bringen wie das mit dem Filter.
    Falls sie doch ein anderes Ergebnis bringt, ist damit erwiesen, dass iwo im Code sich nicht an die Persistenz-Strategie gehalten wird.
    Da sollte man eine Exception werfen.
    Dieses wäre glaub anzusiedeln im Else-Zweig des erwähnten Select Case, odr?

    Etwas unsicher binnich, ob der ChangeTracker Unchanged Rows nicht doch bringt - von einer Klasse namens ChangeTracker kann man sowohl das eine als auch das annere erwarten.
    (Falls er Unchangeds auch erbringt, wären die natürlich auszufiltern)

    Mono schrieb:

    Bei Codefirst gibt es wohl vernünftige Migrationsmöglichkeiten schon von Haus aus mit so einem Migration Tool.

    In meinem Beispiel von dem anderen thread (dem codeFirst VS Modelfirst) habe ich eine automatische Migration eingebaut. diese gibt es nur bei Codefirst. Hier wird beim start das DB Model mit dem des Codes abgeglichen (zur Laufzeit) und evtl. Migriert.

    Mono schrieb:

    Letztlich scheint mir CodeFirst deutlich flexibler zu sein auch wenn es (aktuell) etwas aufwändiger ist und ich gehe davon aus das sich das auf lange Sicht auch durchsetzt.

    Im neuen EF Core ist NUR noch codeFirst enthalten. Auch hier kann nur durch Tools von Drittanbietern hantiert werden.

    ErfinderDesRades schrieb:

    dieselbe Ergebnismenge liefert wie
    VB.NET-Quellcode

    ChangeTracker.Entries().Where(Function(e) TypeOf e.Entity Is ModelBase AndAlso e.State <> EntityState.Detached AndAlso e.State <> EntityState.Unchanged)

    Weil Unchanged wird ein ChangeTracker doch eh nicht liefern, oder?

    Falsch.
    Ruft du Daten ab änderst diese aber nicht sind diese Unchanged.
    Du kannst aber auch jederzeit Entitäten Datachen. diese müssen dann ja nicht durchlaufen werden oder. Also wozu soll ich diese auch abrufen?

    Wenn du Unchanged mitselektierst bekomst du unter umständen 1000e Entitäten hinein.

    Und wegen den gelöschten. Du vertauscht jetze etwas. Ja, es werden alle nur als gelöscht merkiert. Weil dies eben in dieser Savechanges Methode geändert wird. Der EntityState wird von Deleted auf Changed geändert und das IsDeleted Property auf True gesetzt sowie der Timestamp gesetzt. Also brauche ich das sehr wohl. Ich denke du hast dir den code nocht nicht angesehen kann das sein?

    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. ##

    hlghyr schrieb:

    Doch das "Unchanged" mit der Beschreibung : "Die Entität wird vom Kontext nachverfolgt und ist in der Datenbank vorhanden. Ihre Eigenschaftswerte unterscheiden sich nicht von den Werten in der Datenbank." widerspricht dem doch.

    Ja. Wenn du einen Datensatz abrufst, aber keine Werte änderst ist die Entität Unchanged, änderst du ein Property ändert sich der State auf Changed.
    du kannst nun irgendwo im Code den State auf Detached ändern. Wenn du nun speicherst werden die in der Entität geänderten Werte NICHT in die DB zurückgespeichert. Weil du hast mit Detach ja gesagt das du das nicht willst. Das ist ein ganz normales verhalten von EF. Würde ich das jetzt mit Selektieren wäre in der Selektion AUCH jeder Entität enthalten welche ich mit .AsNoTracking abrufe weil EF diese dann NICHT dem ChangeTracker hinzufügt. Ich habe ja gesagt das ich alle Entitäten welche in der Abfrage betroffen sind NICHT tracken möchte.

    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. ##

    hlghyr schrieb:

    Es war ein Fehler von mir. Aus irgend einen Grund hatte ich die Operatoren falsch interpretiert.

    Nene, um Gottes willen. Dafür ist der Thread ja da. Wenn dir irgendwas unklar ist Frage bitte einfach. Ausserdem hätte es ja gut sein können das ich da Mist drinnen hab.

    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. ##

    @ErfinderDesRades

    Da du bis jetzt kein einziges Commit gemacht hast..... darf man davon ausgehen das sich dieses Thema erledigt hat oder hast du einfach gerade wenig Zeit?

    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. ##