Datenbank mit EF Core 2

  • C#
  • .NET 4.5

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von hlghyr.

    Datenbank mit EF Core 2

    Hallo Forum!
    Habe mich mal bei gemacht und ein kleines Projekt erstellt. Unter anderen befindet sich darin das Repository und UnitOfWork Pattern, ein Beispiel für Unit Testing, eine Lokale Sql Datenbank mit dem Entity Framework Core 2 und die Migration.
    Im Anhang findet Ihr die Projektmappe.
    Wenn Ihr die Projektmappe entpackt und startet, werdet ihr erstmal mit Fehlern überschüttet. Das kommt, weil ich die Packages nicht mitgeliefert habe.
    Die bekommt ihr, indem ihr im Projektmappen-Explorer mit der rechten Maustaste auf die Projektmappe (oberste Zeile) klickt und Nuget-Pakete wiederherstellen auswählt. Nach einiger Zeit (220MB) müssten alle Fehler verschwunden sein.
    Ist das der Fall, öffnet die Paket-Manager-Konsole und gebt add-migration ein. Ihr werdet dann nach einen Namen gefragt. Da gebe ich immer "Initial" ein. Es sind auch andere sinnvolle Namen möglich. Nun kann die Datenbank erzeugt werden. dazu gebt in der Paket-Manager-Konsole update-database ein. Wenn ihr jetzt euren Sql Server-Objekt-Explorer öffnet und eine Verbindung zu eurer localdb habt, müsstet ihr nach dem Aktualisieren des Servers die Datenbank "ShopCore2" sehen.
    Ich hoffe das ein wenig Interesse daran besteht und für Anregungen und Fragen hab ich ein offenes Ohr.
    Bei Interesse werde ich genauer auf das Projekt eingehen und es auch erweitern.
    Dies ist für mich nur ein Versuchsprojekt zum üben. Es ist aber voll funktionsfähig und soll ein paar Anregungen geben.
    Gruß Helge
    Dateien
    • ShopEfCore2.zip

      (6,89 MB, 12 mal heruntergeladen, zuletzt: )
    Hi,

    habe es mir gerade kurz angeschaut und denke es ist eine vernünftige Umsetzung des Patterns. Auch wenn ich denke das dein Beispiel noch kein Fall für ein UoW/Repository Pattern ist.
    Eventuell kannst du ja ein bissl darauf eingehen, wozu/wann diese Pattern überhaupt sinnvoll sind bzw die Hintergedanken dazu.
    Generell sieht es ein bissl aus wie ein Fall für den SourceCode Austausch oder Tutorials. Oder was genau möchtest du mit dem Post bezwecken?

    LG
    Das ist meine Signatur und sie wird wunderbar sein!
    Hi!
    Das ich bei diesen Beispiel mit Kanonen auf Spatzen schieße, ist mir völlig klar. Mir ging es da mehr um die Arbeitsweise. Im Prinzip bezieht sich das auch auf diesen Post.
    EntityFramework: CodeFirst vs. ModelFirst
    ---Aus irgend einen Grund bekomme ich den Link nicht hin.---
    Ich finde es ein bisschen Schade das den Datenbanken so wenig Beachtung gegeben wird und ich hoffe durch ein paar Beiträge diese den Leuten näher zu bringen.
    Demnächst werde ich mal ein kompletten ausführlichen Beitrag erstellen.
    Wann das UoW/Repository Pattern sinnvoll ist und wann nicht, muss jeder für sich selbst entscheiden. Bei dem Beispiel macht es wenig Sinn, Weil der Aufwand zu groß ist. Aber je größer die Anwendung, je mehr Sinn macht dieses Pattern. Ich wollte damit auch nur Zeigen, wie man es machen kann. Eine größere Anwendung hätte es nur unübersichtlich gemacht. Ich benutze es sehr oft, da es sich leicht anpassen lässt. Gerade beim entwickeln kann man fast ohne Probleme Projekte leicht erweitern und verwerfen. Dazu kommt noch, wenn man sich so ein Pattern angewöhnt hat, man es nicht mehr missen möchte.
    Kann mir einer bei dem Link helfen? Habe den link vom besagten Post kopiert und auf link einfügen geklickt. Habe noch im sich öffnenden Fenster "URL" , "HTTP" eingestellt und den Link eingefügt. Dann auf Ok gedrückt. Aber es ist nichts passiert. Keine Reaktion.

    Gruß Helge
    Muss jetzt Bier trinken gehen!
    ​Ohh! Hat doch mit den Link geklappt. Aber welche Methode da funktioniert hat, muss ich noch ergründen.
    Hallo @hlghyr

    Erstmal, super das sich mal jemand einem UnitOfWork annimmt. Ich selber verwende gerne UnitOfWork sogar in Verbindung mit MVVM, also unter dem MVVM noch die UnitOfWork Schicht(en).
    Da du schreibst das es ein Versuch von dir was und du gerne Feedback hören möchtest gebe ich meinen Senf mal dazu. Erstmal, nach meinem Wissensstand (ich bin ja auch ken Profi) sehe ich das so das du das Pattern erstmal richtig verstanden und aufgebaut hast.
    Es freut MICH auch sehr das endlich mal jemand mit UnitTests arbeitet und/oder überhaupt daran denkt eine Anwendung so auszubauen das diese Testbar ist/wird. Ich selbst baue keine Anwendung mehr ohne UnitTests, die möchte man nämlich wirklich nicht mehr missen.

    So, ein paar Ideen habe ich dennoch für dich wie du dir das leben einfacher machen kannst.
    Deine Schnittstellen sind fein und auch gut so, ich weis ja auch den Hintergrund warum du diese verwendest. Damit dein Repository Testbar wird. OK. Aber du kannst dir hier eine menge Arbeit ersparen.
    In deinem Fall mit dem IArtikelRepository ist es nämlich so das du für jede Methode welche du im ArtikelRepository einbauen willst dann auch im Interface die Methode erstellst richtig????
    Änderst du einen Parameter muss du das Interface auch wieder ändern. Gibt es einen Grund dafür?? Testbar ist es ja auch so oder?

    Dein IRepository/Repository:
    Du hast das Prinzip verstanden, das Repository ist Generisch und stellt die "Grundfunktionen" bereit. (GettAll, FindBy, Delete, usw.)
    Allerdings ist es so das du z.b. GetAll As List(Of T) NIE verwenden wirst, weil man eigendlich so gut wie nie alle Daten abruft. In einer großen Anwendung wäre das ja ein Performancefehler hoch 3.
    Außerdem bist du mit deinem Respository ZU unflexibel. Gerade bei EntityFramework als auch z.b. wenn ein REST als Datenbackend fungiert gibt es hier andere möglichkeiten.
    Beispiel: Du möchtest ALLE Datensätze abrufen wo die Artikelbezeichnung mit "Ostern" beginnt. In deinem Fall benötigst du nur für diese eigendlich dumme Abfrage WIEDER eine Funktion in deinem IArtikelRepository. Diese muss dann im ArtikelRepository wieder implementiert werden damit dann die Abfrage um diesen Filter erweitert werden kann. Du machst also die ganze Zeit nix anderes als immer wieder "durchzureichen" was keinem Entwickler viel spaß macht.

    Vorallem wenn man bedenkt das man vieleicht noch eine Businesslogik und ein ViewModel davor hängen hat. Immer wieder durchreichen....

    Natürlich will ich nicht nur blöd reden sondern auch zeigen welche, da ich hoffe es interessiert dich.

    Hier ein Beispiel für eine GetAll Methode welche etwas flexibler ist:

    VB.NET-Quellcode

    1. Public Overridable Function GetAll(Optional tracking As Boolean = False) As IQueryable(Of T) Implements IGenericRepository(Of T).GetAll
    2. Dim query As IQueryable(Of T) = CType(_currentContext, MyContext).[Set](Of T)()
    3. If tracking Then query = query.AsTracking
    4. Return query
    5. End Function


    Der Vorteil hier. JEDES Repository kann nun mit GetAll viel besser umgehen. Nun benötigst du in deinem ArtikelRepository die Methode GetPremiumArtikel() gar nicht mehr.
    Weil nun dein Programm sobald es ArtikelRepository instanziert hat wie folgt einfach alle Premiumartikel abrufen, und kann dabei sogar entscheiden ab wann ein Premiumartikel ein solcher ist.
    Ausserdem kann es ja nach bedarf sogar entschieden wie Sortiert und Gruppiert wird. Auch eine Projektion ist möglich weil alle Spalten abzurufen ist ja oft ein Performancefehler. Siehe Beispiel

    VB.NET-Quellcode

    1. Dim artikellist As List(Of Artikel) = repArtikel.GetAll(False).Where(Function(a) a.Preis >= 100) _
    2. .OrderByDescending(Function(o) o.Name) _
    3. .Select(Function(s) New Artikel With {.Name = s.Name, .Preis = s.Preis}).ToList


    OK, das war das eine. Weiters möchte ich darauf eingehen das du den DbContext in deine UnitOfWork-Klassen hineinreichst. OK, das scheint nun auf den ersten Blick nicht weiter schlimm zu sein geht aber am Sinn der UnitOfWork Sache irgendwie vorbei. Ziel ist es ja unter anderem bei UnitOfWork die Trennung zwischen Repository und UnitOfWork (Ähnlich wie bei MVVM). Bedeutet, tausche ich nun das EntityFramework gegen z.b. ein Webservice muss die Anwendung weiterlaufen. Deine Anwendung hätte aber einen Verweis auf das EntityFramework. Sonst könne ich es ja belassen wie es ist denn EntityFRamework ist ja ohnehin im UnitOfWork geschrieben. Ziel ist es (vorausgesetzt das die Layer auch wirklich getrennt sind, also in verschiedene Assemblys) das die Anwendung, Businesslogik und ViewModel KEINEN Verweis auf das EntityFramework haben. Dein UnitOfWork sollte Beispielsweise schon gar nix mehr vom Context wissen.

    OK, jetzt denkt man sich, wie soll ich dann Testen, ich muss da den InMemory-Provider hineinbekommen. Wie Dispose ich dann usw.
    Gerne kann ich anhand eines Beispiel zeigen wie ich das Handhabe (ist aber ne menge Arbeit), würde aber nun den Rahmen dieses Beitrags sprengen. Ausserdem weis ich ja nicht ob du es SO genau machen willst oder ob die ein oder andere "Patternverletzung" für dich sowieso ok ist. Nicht jeder möchte die Trennung so schön haben oder muss nach oben Skalierbar denken.

    Kleine Anregung, die UnitTests sollte man noch ein wenig genauer machen, damit andere mal sehen wie genial die eigendlich sind. :thumbup:
    Du fragst ab wieviele Artikel kommen. Kommen auch die richtigen? Kommen sie in der richtigen Reihenfolge usw. Das sind hald Sachen die muss man wirklich in einer echten Anwendung AUCH Testen.

    So, genug klugges...ssen. :P
    Ich will mit diesem Post echt nicht klugschei..en oder den Professor spielen, ich weis nur wie ich damals das ganze mit EF ausgeknobelt habe und wie schwer das war. Auch weis ich wie ich dann über mehrere "Designfehler" meines Repositorys gestolpert bin. Ich will dir und anderen das ersparen ohne dich dabei aber zu entmutigen. Sorry falls ich so rüberkomme. Keine Absicht. Ehrlich.

    Schöne Grüße und ein Tipp noch..... bleib drann, es lohnt sich, mit einem UoW und/oder eine Repository zu arbeiten ist sooo angenehm auf dauer.
    Sascha

    PS: Sorry wenn ich manchesmal was falsch schreibe, ich muss immer umdenken weil ich es bei mir nicht UnitOfWork benannt habe. Da EF ja im Grunde bereits UoW ist habe ich einfach ein generisches Repository und eine Businesslogik.

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

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

    Hallo @hlghyr

    Aufgrund der stille vermute ich mal das du dich vor den Kopf gestoßen fühlst. Das war echt nicht meine Absicht.
    Ich wollte nur zeigen das ein Repository wenn es IQueryable zurückgibt viel flexibler ist und mit weniger Aufwand und Boilerplate-Code verbunden ist.

    Sorry falls es falsch rüberkahm.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.
    @seh
    Gehört jetzt nicht unbedingt hier her aber...
    Bis ja kein Spanner! 8o Ich selbst bin aber auch öfters "unangemeldet" unterwegs.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.
    Hi Nofear23m!
    Sorry, das ich so lange nicht reagiert habe. Hatte vor fast einen Jahr ein bösen Unfall. Wobei ich mir einen Nerv verletzt habe. Dieser macht mir große Probleme und die Medikamente setzen mich dann Zeitweise außer Betrieb.
    Über deine Antwort habe ich mich sehr gefreut. Normalerweise sieht mein Repository auch etwas anders aus. Der Einfachheit wegen hab ich es bloß so Minimal gemacht.
    An ein Beispiel für die richtige Trennung von Repository und UoW wäre ich sehr interessiert.
    Mir fällt es immer noch schwer, zu entscheiden, was die richtige oder auch günstigste Herangehensweise ist. Hab mich mal ein wenig mit IoC beschäftigt. Denke mal, das das ein vernünftiger Weg ist. Was meinst du dazu?
    Ansonsten hab ich mein altes Projekt auf EF Core umgestellt. Die n:m Beziehungen haben mich etwas zu schaffen gemacht. Ist halt noch umständlich. Hänge mal ein Beispiel mit ran.
    Wenn meine Arbeit kritisiert wird, sehe ich das nicht als Beleidigung. Es hilft mir nur mich zu verbessern.
    ​Die Herangehensweise für das Projekt ist wie im ersten Post. Nur der Name der Datenbank lautet N_MDb und in der Paket-Manager-Konsole gebt nur update-database ein.

    gruß Helge
    Dateien