Unit of Work und Repository - GetAll Methode mit generischer Klasse und Filter

  • VB.NET

Es gibt 61 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    Hallo

    kaifreeman schrieb:

    Am Delete gefällt mir nicht das ich mir das eigentlich bereits vorhandene Object nochmals aus der DB holen muss, wäre es hier nicht einfacher das bereits in der Viewmodel Klasse vorhandene Object vom Typ Entität doch zugänglich zu machen?
    Ist wahrscheinlich mehr eine Optik geschickte es würde halt eine Query ersparen...

    Wenn deine Get Methode des Repository der Wrapper für Find des DBContexts ist was ich vermute wird in diesem Fall kein Query abgesetzt.
    EF Core fürt bei Find(id) NUR ein Query ab wenn er die Entität mit der ID noch nicht im ChangeTracker hat. Fundet er die Entität allerdings im ChangeTracker holt er sie aus diesem und führt keinen Routrip zur DB aus. :thumbup:
    Das sind so die Feinheiten des EF COre die man wissen muss. Deshalb die Empfhelung des Buchs.


    DbContext.Find

    Finds an entity with the given primary key values. If an entity with the given primary key values
    is being tracked by the context, then it is returned immediately without making a request to the
    database. Otherwise, a query is made to the database for an entity with the given primary key values
    and this entity, if found, is attached to the context and returned. If no entity is found, then
    null is returned.


    Ein Tipp von mir. Benamse die Methoden des Repository so wie die von EF, ist transparenter aber das ist evtl. geschmacksache.

    kaifreeman schrieb:

    Tja ich hatte per Default den ChangeTracker deaktiviert... (Optional trackings as boolean war false)

    Ah, dann hast du den Code wohl von meinem Repository. Ja, ich schalte den immer ab und übergeben falls benötigt ein True an die Methode wie z.b. der GetAll Z.b. würde ich mit GetAll(True) das Tracking für dieses Query einschalten. ACHTUNG: Das Thema ChangeTracking ist ein riesen Performancethema - mich wundert das MS ihn nicht per Default sogar abschaltet. Ohne Changetracker ist EF Core nochmal mehr als doppelt so schnell. Nur so am Rande. Aber wie gesagt - Buch!

    kaifreeman schrieb:

    So mit dem Wissen werde ich jetzt mal meine Anwendung umbauen muss mir auch noch das Thema DBContext und Migration von EF Core geben, schade das EF Core Migration VB nicht unterstützt und man eine C# Klasse basteln muss.

    Tipp von mir - siehe HomeStorage. Den DB Context und nur diesem als eigene Assembly erstellen. So kannst du alles andere wie das Model ruig in VB machen. Ich finde es jetzt nicht so schlimm, klar man fühlt sich als VBler ausgeschlossen aber gut, mit der einen Klasse kann ich leben.

    Schöne 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. ##

    Stimmt das vergesse ich ja immer, muss mich erst daran gewöhnen das die UoW ja nicht immer mit der Datenbank kommuniziert wenn etwas ausgeführt wird.
    Das Buch habe ich schon bestellt danke für den Tipp :)

    Zum Thema ChangeTracker, interpretiere ich das richtig das der Changetracker wie in deinem Fall beschrieben GetAll(True) in dem Fall dann permanent für diese Query aktiv ist? Wenn ja macht es definitiv Sinn ihn immer abzuschalten gibt ja genug Situationen wo changeTracking nicht erforderlich ist.

    Danke für den Tipp hab mir schon viel von deinem HomeStorage abgeguckt. Auf die Implementierung von IProtocolable freue ich mich, sehr gutes Beispielprogramm noch ganz nebenbei erwähnt :)

    Letzte Frage noch weil es mir gerade beim Tippseln kommt.
    Wie geht man eigentlich am besten mit den Navigation Properties um? Im Beispielprogramm habe ich ja alle rausgeschmissen zwecks Vereinfachung.
    Wäre es dann so das ich im ViewModel die Navigation Property so "nachbaue" das sie ebenfalls das ViewModel der Entsprechenden Enttität abbildet?

    Beispiel:
    Foo FooVM 1:n Bar BarVM

    Navigation Property dann im FooVM => Public Overridable Property NVBars as observablecollection(of BarVM) oder Public Overridable Property NVBars as observablecollection(of Bar)
    mfG.
    Stephan
    Hallo

    kaifreeman schrieb:

    Zum Thema ChangeTracker, interpretiere ich das richtig das der Changetracker wie in deinem Fall beschrieben GetAll(True) in dem Fall dann permanent für diese Query aktiv ist?

    Naja, ich habe es im HomeStorage ja so implementiert das im Repository die Signatur von z.b. GetAll als Parameter das Tracking eingeschaltet werden kann. Wird dies gemacht wir das Tracking für DIESES Query eingeschaltet.
    Also werden die Datensätze welche mit der ausführung dieses Querys getrackt. Und NUR diese. Beim nachsten ausführen von GetAll ohne Parameter oder mit False als Parameter eben nicht.
    So kannst du von Fall zu Fall entscheiden ob du Tracken willst oder nicht.
    Weiters habe ich im HomeStorage einen Konstruktor mit welchem man das Tracking für die Instanz des DBContexts einschalten kann. Das gilt dann für die Zeit die die Instanz des DBContext "lebt".
    Außerdem kann man das Tracking für die DBContext instanz generall aus/einschalten mit dem Property ChangeTrackerTrackAll falls man es mal benötigt.
    Du siehst, ich habe mir da schon ein paar Gedanken gemacht. :huh:

    kaifreeman schrieb:

    Auf die Implementierung von IProtocolable freue ich mich, sehr gutes Beispielprogramm noch ganz nebenbei erwähnt

    Ja, das ist auch ziemlich cool. Sag bescheid wenn du dort angelangt bist, hier habe ich ein kleines "Zuckerl" für dich um die Protokollierung und einen vollständigen Änderungverlauf im VM zu automatisieren so das du auch daran nicht mehr denken musst. :thumbup: Hab mir da mal was ausgedacht. ;)

    kaifreeman schrieb:

    Wie geht man eigentlich am besten mit den Navigation Properties um?

    Also im Model am besten die Navigation Properties immer als Overridable und mit dem Typ ICollection(Of Foo) erstellen.
    Und ja ublic Overridable Property NVBars as observablecollection(of BarVM) ist richtig, sonst würden wir ja WIEDER das Model an die View weiterreichen.

    Das ist auch der Grund warum ich Anfängern von MVVM immer empfehle die Projekte wie im HomeStorage zu trennen. Also in getrennte Assemblys zu packen. Hast du dann nämlich unabsichtlich solch einen Designfehler merkst du es gleich da du plötzlich im View einen Verweis auf das Model benötigen würdest. Spätestens da merkt man gleich das was nicht passt und sieht sich das nochmal an.
    Mal abgesen davon das du das Model vieleicht in einem anderen Programm oder einer Testapp oder sowas nochmal benötigen könntest. Und dann ist es ja gut wenns extra verpackt ist.

    Langsam gehts aber mehr ums EF und um MVVM. Vieleicht ein neuer Thread? Nicht das du glaubst ich will nciht mehr Antworten, aber ich meine nur wegen dem Forum.

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

    Hallo

    Hast du diesbezüglich noch Fragen wegen den NavigationProperties oder passt soweit alles? Wirst sehen, bist du da mal "drinnen" willst du nicht mehr anders proggen.

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

    Hallo Sascha,

    sorry für meine verspätete Antwort, ich habe den ganzen Sonntag verballert um mein Projekt jetzt angelehnt an Homestorage aufzubauen. Da ist mehr Zeit draufgegangen als gedacht aber es hat sich definitiv gelohnt, wenn man den Pattern konsequent anwendet kristallisiert sich "gefühlt" die Trennung der Schichten immer besser heraus.

    Aktuell habe ich jetzt für alle Entitäten die Viewmodels zum Thema hinzugefügt.
    Habe alle Repositories überarbeitet und bastel gerade an den Viewmodels für normales AddEdit und Overview.

    Soweit scheint alles noch zu klappen. Ich habe jetzt aber auch noch keine Navigation Property erprobt das sollte ich vermutlich bis Ende der Woche soweit haben.
    Wenn es ein Problem gibt melde ich mich gerne wieder.
    Bis dahin danke nochmals für einen Einsatz und deine Geduld, in diesem Thread habe ich echt extrem viel gelernt.

    Ps: Heute ist das von Holger Schwichtenberg angekommen, bin schon gespannt darauf es zu lesen.

    lg
    Stephan
    mfG.
    Stephan
    Achso. Ne, kein Problem. Lass dir ruig Zeit. Gut ding braucht weile.

    Das mit den NavigationProperties schaffst du auch noch.

    Ich wünsche dir viel spaß mit dem Buch, ich habe es einem Freund auch empfohlen und der hat es richtig verschlungen und auch ich habe alleine dieses Buch von Herrn Schwichtenberg sicher drei mal komplett(!!) durchgelesen und da passiert bei einem Buch recht selten das man wirklich jedes Kapitel durchgeht. Er erklärt wirklich gut und einfach.

    Schöne 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. ##

    Morgen,

    so jetzt hab ich das mit den Navigation Properties getestet aber es will nicht ganz so wie ich das will. Ich habe es geschafft die Navigation Property aus der Datenbank zu laden aber das Viewmodel wird dadurch nicht wirklich beeinflusst.
    Ich habe hier eine Entität User die über eine Join Tabelle mit UserGroup verbunden ist die Join Entität ist UserUserGroup

    Damit suche ich den User per ID in der Datenbank und lade mit LoadCollection die Navigation Property:

    VB.NET-Quellcode

    1. Private Function GetUserVMByID() As Boolean
    2. If UserID = Nothing Then Return False
    3. If CurrentUser IsNot Nothing Then Return False
    4. Using _UnitOfWork As New UnitOfWork(True)
    5. Dim vUser As User = _UnitOfWork.UsersRepo.Find(UserID)
    6. _UnitOfWork.UsersRepo.Attach(vUser)
    7. If vUser Is Nothing Then Return False
    8. _UnitOfWork.UsersRepo.LoadCollection(vUser, "NvUserUserGroup")
    9. CurrentUser = New UserVM(vUser)
    10. Debug.Print(CurrentUser.NvUserUserGroup.Count.ToString)
    11. End Using
    12. Return True
    13. End Function

    Der User wird dann als User Viewmodel an eine Singleton übergeben die CurrentUser beinhaltet ( die Funktion ist in dieser besagten Singleton Klasse).

    In meinem UserViewmodel habe ich im Sub New folgende Definition:

    VB.NET-Quellcode

    1. Public Sub New()
    2. End Sub
    3. Friend Sub New(__BaseItem As User)
    4. _BaseItem = __BaseItem
    5. End Sub


    Logischerweise passiert hier aber mit der Navigation Property nichts das __Baseitem zu übergeben ist nicht ausreichend für diese Navigation Property:

    VB.NET-Quellcode

    1. Public Overridable Property NvUserUserGroup As New ObservableCollection(Of UserUserGroupVM)


    Jetzt habe ich mir gedacht ich mache folgendes:

    VB.NET-Quellcode

    1. Friend Sub New(__BaseItem As User)
    2. _BaseItem = __BaseItem
    3. For Each Item As UserUserGroup In __BaseItem.NvUserUserGroup
    4. NvUserUserGroup.Add(New UserUserGroupVM(Item))
    5. Next
    6. End Sub

    Das funktioniert soweit aber hier ist der Punkt wo ich mir die Haare raufe.

    Der gesamte Logische Tree schaut ja so aus:
    n User : m Benutzergruppen
    1 Benutzergruppe : n Berechtigungen

    Ich habe jetzt zwar die Navigation Property für die Usergroup aber was ist mit den anderen Navigation Properties?
    Ich kann jetzt zwar im Konstruktor jedes Viewmodels das machen aber spätestens beim Konstruktor der Join Tabelle:

    VB.NET-Quellcode

    1. Friend Sub New(__BaseItem As UserUserGroup)
    2. _BaseItem = __BaseItem
    3. NvUser = New UserVM(__BaseItem.NvUser)
    4. NvUserGroup = New UserGroupVM(__BaseItem.NvUserGroup)
    5. End Sub


    Läuft er in einen Stackoverflow da das ganze sich ja immer wieder selbst aufruft....
    mfG.
    Stephan
    Hallo Kai

    Ich verstehe die problemantik und kann dir soweit folgen, es ist aber schwer zu sehen wo nun den Denkfehler ist wenn man nur ein paar aus dem Kontext gerissene Codezeilen sieht.
    Kannst du das Projekt mal hochladen bitte damit ich mir das ansehen kann?

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

    Hallo Sascha,

    so ich habe jetzt ausnahmsweise wirklich die komplette Solution angehängt und nicht ein neues Programm erstellt.
    Ich habe hier versucht die logische Struktur von deinem Homestorage nachzubauen.
    Die Repo Klassen habe ich aktuell mal komplett von dir übernommen (ich werde sie später noch umschreiben nur wollte ich vorher den Pattern verstehen bevor ich mir noch mehr Sargnägel einbaue ;) ).

    Zur Überlegung hinter dem Programm einige Informationen:
    Beim Programmstart wird in der "OnStartup" Sub eine Loginform angeboten.
    Aus den Angaben von dort wird ein Connectionstring gebildet und in den Connectionstrings gespeichert.
    Danach wird mit der UnitofWork der Benutzer aus der Datenbank gesucht.
    Hier beginnt quasi die erste Interaktion der Datenbank mit dem Viewmodel.
    Die Function "GetUserVMByID" nutzt wiederum die UnitofWork um die Daten abzuholen und ans Viewmodel zu geben.

    Genau hier beginnt mein Problem, wenn ich jetzt für jede Entität jede Navigation Property einzeln laden muss dann ist das nicht Praktikabel.
    Ich denke nur an den Artikelstamm der hat eine Vielzahl an Navigation Properties da wird das laden dann echt unangenehm.

    Ich habe gelesen das im neuen EF Core LazyLoading implementiert ist, natürlich ist das eine mögliche einfache Variante aber gemäß Definition muss der DBContext dann am Leben erhalten werden...


    Was mir aktuell bewußt ist was in meiner Solution nicht passt:
    - UnitofWork liegt im BL sollte eher im DAL vorhanden sein
    - View ist in der App => muss noch ein eigenes Projekt View hinzufügen
    Dateien
    • MyERP2.7z

      (1,02 MB, 84 mal heruntergeladen, zuletzt: )
    mfG.
    Stephan

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

    Hallo Kai

    kaifreeman schrieb:

    Das Forum unterstützt leider keine geteilten Archive die Datei MyERP2_001.7z muss daher in MyERP2.7z.001 und Analog die 002 umbenannt werden.

    Bitte das nächste mal auf "Projekt bereinigen" in VS klicken. Angehängte Projekte nämlich immer ohne "Packages" sowie ohne "bin" und "debug"-Ordner hochladen.
    Dann hat der Anhang auch nur ein paar KB und du sparst dir das Splitten von Archiven.

    kaifreeman schrieb:

    Ich denke nur an den Artikelstamm der hat eine Vielzahl an Navigation Properties da wird das laden dann echt unangenehm.
    Ne, geht einfacher.

    Ich habe gelesen das im neuen EF Core LazyLoading implementiert ist, natürlich ist das eine mögliche einfache Variante aber gemäß Definition muss der DBContext dann am Leben erhalten werden...

    Sollte eigendlich vermieden werden. Siehe Buch von Holger. Ich selbst bin auch kein Freund davon. EF 6 hatte das schon drinnen und das ist der performancekiller schlechthin. Einmal nicht aufgepasst und du hast die halbe DB im Ram. Nicht gut.

    Ich schau mir das dann gleich mal an, mal sehen. Bitte nicht böse sein wenns erst am Nachmittag ist.

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

    Hallo Sascha,

    Ups, dachte das bereinigen die BIN mitlöscht habe die Solution neu hochgeladen.

    Nofear23m schrieb:

    Sollte eigendlich vermieden werden. Siehe Buch von Holger. Ich selbst bin auch kein Freund davon. EF 6 hatte das schon drinnen und das ist der performancekiller schlechthin. Einmal nicht aufgepasst und du hast die halbe DB im Ram. Nicht gut.

    Das würde ja bedeuten ich müsste alles über Queries abdecken?? Mit anderen Worten wenn ich die Benutzergruppen für den Benutzer brauche => Query um alle Rechte der Gruppen zu holen => Query... das wäre ja irgendwie ein Drama...
    Ok gut ich meine ich verstehe schon das ich mir den RAM nicht "zumüllen" will aber wenn ich immer brav mein Viewmodel Dispose wenn ich es nicht mehr brauche sollte das eigentlich kein Thema sein, oder verstehe ich das falsch?

    Nofear23m schrieb:

    Bitte nicht böse sein wenns erst am Nachmittag ist.

    Bitte du opferst deine Freizeit um mir zu helfen! Bin froh das du noch die Geduld aufbringst :
    mfG.
    Stephan

    kaifreeman schrieb:

    Das würde ja bedeuten ich müsste alles über Queries abdecken?? Mit anderen Worten wenn ich die Benutzergruppen für den Benutzer brauche => Query um alle Rechte der Gruppen zu holen => Query...

    Ne, keine Angst, so kompliziert ist es dann nicht. Ich bau dir da was ein.

    kaifreeman schrieb:

    Ok gut ich meine ich verstehe schon das ich mir den RAM nicht "zumüllen" will aber wenn ich immer brav mein Viewmodel Dispose wenn ich es nicht mehr brauche sollte das eigentlich kein Thema sein

    Es geht ja nicht nur um den RAM. Man sollte auch immer darauf achten was man übertragen bekommt.

    Lese ich z.b. aus ob jemand ein gewisses recht hat hole ich mir auch nicht die Rechte für einen User von der DB und prüfe das dann lokal mit dem aktuell benötigtem Recht ab.
    Ne, ich überlasse die Arbeit dem SQL Server, der macht das besser. Ich frage den SQL Server ob der User XY das Recht Z besitzt. Der gibt mir True oder False zurück.
    Also anstatt das ich 30 Datensätze mit jeweils vieleicht 10 Spalten von Server zum Client übertrage bekomme ich True oder False zurück. Solche optimierungen merkt man dann spätestens wenn die Connection mal über ne 8 MBit WAN Leitung läuft. 8|

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

    Hallo Kai

    Also erstmal hut ab. Hast du dir nicht die Finger wund getippt?
    Wahnsinn was du alles schon für ViewModel Klassen drinnen hast und wieviele Repositories. Unglaublich!!

    Das muss ja arbeit sein. Ein Tipp von mir. Erst immer weitermachen wenn ein "System" funzt. und man sicher ist man ist am richtigen weg.
    Warum sooo viele VMs wenn du gar nicht weist ob diese Basisklasse passt oder ob du mit dem MVVM Light zurechtkommst. Du musst ja nicht alle erstellen das dein Projekt kompiliert.
    Genauso die Repositories. Die hättest du dir alle sparen können. Du hast ja ein generisches Repository erstellt. In diesem Fall benötigst du die alle nicht. Ich habe auch erst diesen kleinen Fahler gemacht. @ThuCommix hatte hier aber ne tolle Idee wie man sich diesen Overhead sparen kann, man muss dann zwar ein bischen Tricksen was gewisse EF Funktionalitäten angeht, es zahlt ich denke ich trotzdem aus. Und zur Not kann man bei bedarf doch eines machen sollte es wirklich notwendig werden.

    Ich hab das alles mal rausgeschmissen zwecks übersichtlichkeit. Keine Angst, habe nur - aus dem Projekt ausschliessen - gemacht.
    Eine Zeit lang habe ich die Änderungen mitgeschrieben.
    • MODEL
      • Diverse List(Of) durch ObservableCollection(Of) ersetzt. Bin nicht alle durchgegangen, nur User. Schau mal im Buch von Holger
    • DBContext
      Der LazyLoading-Parameter im Context ( optionsBuilder.UseLazyLoadingProxies ) hat das problem verursacht das die NavigationPropertys nicht geladen wurden.
      Auch ein Grund warum ich das Ding nicht mag. Das funzt nur wenn die Klassen dementsprechend aufbereitet sind.
    • CONNECTIONSTRING
      Eine Signleton KLasse erstellt (Instance.vb) welche Programminstanzweit den aktuellen Connectionstring hält.
      Im Context dann natürlich diesen anstatt dem aus dem Configfile verwendet
      Der Vorteil gegenüber der Configdatei: Du kannst eine zweite Programminstanz mit einem anderen Connectionstring starten ohne das die erste Instanz plötzlich auch diesen verwendet!!
    • BL
      Warum hat die BL einen Verweis auf das EntityFramework?
      Soll sie ja gar nicht haben.
      Habe ich alles mal rausgeschmissen!!
    • Basisklasse (BlBase) hinzugefügt



    Aber eigendlich sind mir ein paar Dinge unklar. Du hast einen BL Layer was ich ganz gut finde, so wird das ViewModel nicht mit Logik zugemüllt und alles bleibt sauber getrennt. Super übersichtlich.
    Du verwendest den Layer nur nicht wirklich. Du hast die ganze Logik des Logins in der Application.vb. Habe eine LoginBl erstellt und alles dort rein gepackt. So ist das aufgeräumt.

    Weiters: Du hast MVVM Light eingebunden. Ich persönlich kenne mich damit nicht aus und kann mich jetzt auch nicht schnell mal einlesen, da mach ich auf die schnelle sicher Fehler, aber warum verwendest du das Framework nicht. Du hast ein LoginFrm, du öffnest MessageBoxen und Fenster in der Application.vb obwohl das (bzw. fast alles davon) eigendlich in ein ViewModel gehört. Jedoch über Services des Frameworks.
    Ich meine OK, das mit dem Login kann man dort schon lassen, aber ich wundere mich nur.

    Im großen und ganzen muss ich nochmal sagen, HUT AB. Also ich habe schon lange keinen mehr gesehen der sich solche mühe gibt und sich solche arbeit macht, respekt - dennoch würde ich sagen - ruig brauner!
    Mach immer ein ViewModel, die BL dazu und den View dazu. Wenn alles gut dann nächstes, ViewModel, die BL , und die View dazu. Und weiter.
    Solltest du auf probleme stoßen geschied dies schon sehr bald, und du musst nur ein paar Klassen "umbauen" und nicht 35 Klassen im VM und 35 Klassen in der BL.

    Ich hoffe dir jetzt nicht den mut und/oder die Freude daran genommen zu haben.

    Anbei das Projekt.
    PS: Kann sein das die ein oder andere Klasse noch drinnen ist welche gar nicht mehr benötigt wird, ich habe nun nicht mehr alle durchgeprüft nachdem ich gefühlte 100 Datein aus der Projektmappe rausgeworfen hatte.

    Grüße
    Sascha
    Dateien
    • MyERP2.zip

      (3,75 MB, 92 mal heruntergeladen, zuletzt: )
    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“ ()

    Hallo Sascha,

    erstmal vielen Dank das du dir soviel Mühe gegeben hast. Ich habe gestern den Code im Detail analysiert und in meine Applikation eingebunden.
    Warum ich aktuell so viele Repos und Klassen habe liegt schlicht und ergreifend daran das ich mein bisheriges Projekt MyERP auf die neue Struktur gezogen habe und dort hatte ich bereits alles soweit am laufen.
    Aktuell fühle ich mich wie ein Neandertaler nach einem Schlaganfall... Irgendwie muss ich gerade alles neu lernen...

    Die Geschichte mit den Navigation Properties funktioniert nur mit dem Login komme ich aktuell überhaupt nicht klar.
    Folgendes wirft bei mir ein Problem auf in deiner Implementierung ist der InstanceHolder im Viewmodel, da kann ich ihn aber vom DAL aus nicht greifen um auf den Connectionstring zu kommen.
    Beim ausführen der LoginVM wird zuerst eine Generic Repo erstellt zu einem Zeitpunkt wo aber der Connectionstring nicht belegt ist, damit wird im DB Context der Connectionstring falsch gelesen.

    Was ich getan habe:
    1. Instanceholder in den DAL verschoben
    2. UserBl Klasse erweiter um eine Sub New:

    VB.NET-Quellcode

    1. Public Sub New(_Server As String, _Database As String, _Username As String, _Password As String)
    2. InstanceHolder.Instance.CurrentConnectionstring = GetConnectionString(_Server, _Database, _Username, _Password)
    3. _repUser = New GenericRepository(Of User)
    4. End Sub

    Hier übergebe ich die Parameter nach dem Login, bastel sofort den Connectionstring und erstelle erst dann das Repository.
    3. Im Generic Repository folgende Anpassung:

    VB.NET-Quellcode

    1. Protected Friend Sub New(Optional _Context As MyERP2Context = Nothing, Optional _Tracking As Boolean = False)
    2. Debug.WriteLine("Create new instance of GenericRepository...")
    3. ' If Context comes externally take this
    4. If _Context IsNot Nothing Then
    5. Context = _Context
    6. _disposeContext = False
    7. Else
    8. Context = New MyERP2Context(InstanceHolder.Instance.CurrentConnectionstring)
    9. End If
    10. ContextInternal.ChangeTracker.AutoDetectChangesEnabled = _Tracking
    11. If _Tracking Then
    12. ContextInternal.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll
    13. Else
    14. ContextInternal.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking
    15. End If
    16. End Sub

    in dieser Zeile:

    Quellcode

    1. Context = New MyERP2Context(InstanceHolder.Instance.CurrentConnectionstring)
    wird bei Erstellung eines neuen Contexts immer der Connectionstring mitübergeben, da die Klasse Instanceholder vom DB Context aus nicht greifbar ist.
    ------------ Damit wäre das Login soweit erledigt -----------------

    Während des Logins wird noch mit

    Quellcode

    1. InstanceHolder.Instance.CurrentUserInfo = bl.GetUserInformationIncludingGroupsAndSettings(vVM.Username)
    der aktuelle Benutzer als Entität "User" in den InstanceHolder übergeben.
    Im Mainviewmodel hole ich mir diesen User und übergebe ihn als Viewmodel:

    VB.NET-Quellcode

    1. Public Property CurrentUser As UserVM
    2. Sub New()
    3. CurrentUser = New UserVM(InstanceHolder.Instance.CurrentUserInfo)
    4. RaisePropertyChanged("CurrentUser")
    5. End Sub


    Da ich alle dem Benutzer zugeordneten Benutzergruppen sehen möchte habe ich im Viewmodel eine Function die mir das erledigen soll (ok hier könnte man jetzt wahrscheinlich besser eine Business Logik verwenden)?

    VB.NET-Quellcode

    1. Public ReadOnly Property AllUserGroups As String
    2. Get
    3. Dim vStrBuilder As New StringBuilder
    4. If NvUserUserGroup IsNot Nothing AndAlso NvUserUserGroup.Count > 0 Then
    5. For Each vItem As UserUserGroupVM In NvUserUserGroup
    6. vStrBuilder.AppendLine(vItem.NvUserGroup.GroupName)
    7. Next
    8. End If
    9. Debug.Print("AllUserGroups:" & vStrBuilder.ToString)
    10. Return vStrBuilder.ToString
    11. End Get
    12. End Property


    hier sind die Navigationproperties wieder nicht belegt und bleiben leer stehen.
    Sitze ich hier einem Denkfehler auf? Muss ich meine Navigationproperties wirklich über den Haufen schmeißen und alles mit der Businesslogik erledigen?

    Bzgl. MVVM Light, ich habe im Zuge meiner Recherchen zu Beginn gelesen das es nicht optimal ist den Messenger zu oft zu nutzen und zu überladen (kann leider nicht mehr sagen wo genau), da ich aber möglichst keinen Code im View Codebehind haben möchten akzeptiere ich lieder das ich das Pattern verletze und die Views über das Viewmodel aufrufe.
    In MVVM Light gibt es einen Navigationservice den ich mir gerade anschaue und implementieren möchte der sollte wahrscheinlich besser funktionieren als den Messenger zu nutzen.

    Genau eines habe ich noch vergessen:
    Du hast in deinem verbesserten Projekt meine UnitofWork rausgekickt. Ich habe beim "erlernen" des Patterns Repositories und UnitOfWork gelesen das man bei Einsatz von Repositories nicht auf die UnitofWork verzichten soll, ist die UoW nur gefallen weil es aktuell nicht notwendig wäre oder bist du der Meinung das eine eigene UoW sinnlos ist? Im Endeffekt kappselt sie ja nur die Repositories..
    mfG.
    Stephan

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

    Hallo Stephan

    kaifreeman schrieb:

    Instanceholder in den DAL verschoben

    Das ist auch korrekt so.

    Sorry, das mit dem InstanceHolder hätte ich dazu sagen sollen. Das war jetzt nur eine schnelle implementierung. In meinen Projekten habe ich diesen in einer eigenen Assembly ohne Verweise auf irgendeine andere Bibliothek.
    Im Context und der BL habe ich diesen InstanceHolder referenziert. Die BL setzt den Connectionstring 1x und der Context liest ihn dann immer wieder aus. So spare ich mir das ständige:

    kaifreeman schrieb:

    Context = New MyERP2Context(InstanceHolder.Instance.CurrentConnectionstring)

    weil der Context direkt die Veriable ausliest.
    Dies hat aber auch zur folge das du CurrentUser so nicht speichern kannst. Sondern nur "normale" Datentypen da diese Assembly keinen Verweis auf ein Model hat.

    kaifreeman schrieb:

    Bzgl. MVVM Light, ich habe im Zuge meiner Recherchen zu Beginn gelesen das es nicht optimal ist den Messenger zu oft zu nutzen und zu überladen (kann leider nicht mehr sagen wo genau), da ich aber möglichst keinen Code im View Codebehind haben möchten akzeptiere ich lieder das ich das Pattern verletze und die Views über das Viewmodel aufrufe.
    In MVVM Light gibt es einen Navigationservice den ich mir gerade anschaue und implementieren möchte der sollte wahrscheinlich besser funktionieren als den Messenger zu nutzen.

    Ich kenne das Framework nicht. Aber auch kein anderes MVVM Framework. Ich war immer der Meinung das man sein eigenes Framework implementieren sollte wenn man MVVM verstehen will.
    Die View ins ViewModel zu reichen ist für mich ein NoGo. Du verlierst sofort alle Vorteile der Layertrennung, also wozu dann noch ein Repository oder eine UnitOfWork

    Das stimmt, die Messages sind nur für bestimmte Dinge. Ich habe auch eine solche Klasse in meinem MVVM "Framework" und muss dir sagen, solange du korrekt MVVM Codest brauchst du gar keine Messages, zumindest nicht mit meiner MVVM Implementation. Ich weis nicht wie das mit MVVM Light aussieht, aber das ist ja eh ein gutes Framework, wenn man mal davon absieht das es unter WPF keinen CommandManager für die RelayCommands nutzt.

    kaifreeman schrieb:

    ist die UoW nur gefallen weil es aktuell nicht notwendig wäre oder bist du der Meinung das eine eigene UoW sinnlos ist? Im Endeffekt kappselt sie ja nur die Repositories..

    Ne, das nicht. Das UnitOfWork ist ein Pattern. Wie du die Klassen dann nennst ist dir überlassen. Im Grunde - nicht ganz genau das selbe aber fast - ist dein Generisches REpository die UnitOfWork.
    Überlege mal. Du hattest für jede Entität eine Repositoryklasse. Also eine UnitOfWork oder?

    Die Repositoryklasse haben wir/du nun aber so generisch gestalltet (was mit EF super funzt) das du diese ganzen Repositoryklassen nicht mal benötigst, also im Grunde besser als eine UnitOfWork.
    Aber... man könnte eigendlich die BL als UnitOfWork bezeichenen. Nicht als generische aber im Grunde ist es ja eine. Unit Of Work. Teil der Arbeit.

    In der LoginBl machst du die Arbeit für den Login. Also den Loginteil. Irgendiwe passt das doch.

    kaifreeman schrieb:

    Da ich alle dem Benutzer zugeordneten Benutzergruppen sehen möchte habe ich im Viewmodel eine Function die mir das erledigen soll

    kaifreeman schrieb:

    hier sind die Navigationproperties wieder nicht belegt und bleiben leer stehen.

    Ich sehe leider keinen Code für das Abrufen der Daten aus der DB. Somit weis ich nicht ob du korrekt abrufst. Wurde der Context vieleicht zwischenzeitlich Disposed? Dann ist der Cache natürlich leer.
    Alles dinge die ich so nicht sehe.


    Meine empfehlung:
    Eines nach dem anderen, du kommst sonst durcheinander und siehst den Wald vor lauter Bäumen nicht mehr.
    Mal alles raus was nicht benötigt wird.

    Dann ein Login-View, das LoginVm und die LoginBl!

    So, und die gehen wir dann gemeinsam durch. Schon im LoginVm musst du SEHR viel machen was zuerst geklärt werden muss ob in in deine Projektstruktur passt.
    Messageboxen werfen, Validierung von Benutzereingaben (ist Username ausgefüllt, hat Passwort mindestens 6 Zeichen usw), einen Dialog vom VM aus öffnen (wenn Passwort abgelaufen um er zu ändern vieleicht) und vieles, vieles mehr.

    Mach das eine VM mal fertig, dann wirdst du sehen - die anderen gehen dann viel leichter und du weist um was es geht.

    Das einzige wo ich dir nicht Helfen kann ist beim MVVM Light.

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

    Abend Sascha,

    Ich habe jetzt den ConnectionHolder in eine eigene Assembly geschoben das funktioniert gut. Morgen werde ich dann noch das Userhandling verbessern.
    Ich denke das die "CurrentUserInfo" Property im ConnectionHolder nichts verloren hat. Ich werde diese dann noch in ein eigenes Singleton packen.
    Mittlerweile ist mir auch klar warum meine Navigationproperties im Viewmodel leer bleiben. Durch das Using Statement kille ich ja immer den aktuellen DBContext.

    Für mich stellt sich daher mittlerweile die Frage ob es nicht besser ist den DBContext als Singleton zu instanzieren so das Programmweit immmer derselbe DBContext genutzt wird.
    Wobei das eigentlich dem Wunsch widerspricht eine minimale Lebenszeit beim DBContext zu haben.

    Für mich habe ich das Problem durch eine eigene UserBL gelöst:

    VB.NET-Quellcode

    1. Imports System.Data.SqlClient
    2. Imports System.Text
    3. Imports Model.MyERP2Model
    4. Imports MyERP2.ConnectionHolder
    5. Imports MyERP2.DAL
    6. Public Class UserBl
    7. Inherits BlBase
    8. Private ReadOnly _repUser As GenericRepository(Of User)
    9. Public Sub New()
    10. _repUser = New GenericRepository(Of User)
    11. End Sub
    12. ''' <summary>
    13. ''' It's possible to pass an existing Repository to use the same dbcontext again.
    14. ''' </summary>
    15. Friend Sub New(rep As GenericRepository(Of User))
    16. _repUser = rep
    17. End Sub
    18. Public Function GetAllUserGroupsofLoggedinUser() As String
    19. If InstanceHolder.Instance.CurrentUserInfo Is Nothing Then Return String.Empty
    20. Dim vCUser As User = InstanceHolder.Instance.CurrentUserInfo
    21. Dim vStrbuilder As New StringBuilder
    22. If vCUser.NvUserUserGroup IsNot Nothing AndAlso vCUser.NvUserUserGroup.Count > 0 Then
    23. For Each vGroup As UserUserGroup In vCUser.NvUserUserGroup
    24. vStrbuilder.AppendLine(vGroup.NvUserGroup.GroupName)
    25. Next
    26. Return vStrbuilder.ToString
    27. Else
    28. Return String.Empty
    29. End If
    30. End Function
    31. Public Function UpdateUserZoom(_ZoomValue As Double) As Boolean
    32. If InstanceHolder.Instance.CurrentUserInfo Is Nothing OrElse _ZoomValue = Nothing Then Return False
    33. Dim vCuser As User = InstanceHolder.Instance.CurrentUserInfo
    34. vCuser.Zoom = _ZoomValue
    35. Using _UoW As New GenericRepository(Of User)
    36. _UoW.Attach(vCuser)
    37. _UoW.Edit(vCuser)
    38. _UoW.Save()
    39. End Using
    40. Return True
    41. End Function
    42. End Class


    Die Function "GetAllUserGroupsofLoggedinUser" holt mir immer meine Benutzergruppen als String, ich arbeite ja nicht mit den Daten sondern brauche sie nur für das View später.
    Die Function "UpdateUserZoom" ist ein als eine Art Test gedacht um Werte nach einer Änderung zurück in die DB zu schreiben. Später werde ich eine "globale" UpdateUserSettings Function erstellen die beim beenden des Programms die Einstellungen in die DB schreibt.

    --------
    Zum UoW => es ist wirklich interessant wie viele Meinungen es zu dem Thema gibt, ich habe wie Eingangs erwähnt einen Udemy Kurs von Mosh Hamedami gesehen, dort weißt er explizit auf folgende Umstände hin:
    Repositories sollten nie Objekte vom Typ IQueryable zurückgeben da nach seiner Auffassung ein Fremder Programmierer glaubt er kann damit eine Abfrage machen, Mosh empfiehlt die Rückgabe eines Queryresults in Form einer ObservableCollection(of ...)
    Simpel ausgedrückt, ich möchte alle User meiner Datenbank haben => in der aktuellen Implementierung würde ich es in die Business Logik packen und dann dort abholen, lt. Mosh würde die Business Logik das Repository Fragen und das Repository macht die Query und gibt das Result zurück.
    Im Endeffekt das selbe Ergebnis aber ein unterschiedlicher Ansatz.

    --------

    Nofear23m schrieb:

    Das stimmt, die Messages sind nur für bestimmte Dinge. Ich habe auch eine solche Klasse in meinem MVVM "Framework" und muss dir sagen, solange du korrekt MVVM Codest brauchst du gar keine Messages, zumindest nicht mit meiner MVVM Implementation. Ich weis nicht wie das mit MVVM Light aussieht, aber das ist ja eh ein gutes Framework, wenn man mal davon absieht das es unter WPF keinen CommandManager für die RelayCommands nutzt.


    Fürs erstellen einer neuen View gibt es ja mehrere Konzepte (mir sind sicher nicht alle bekannt) aber zumindest was ich kenne:
    1) Serviceklasse die das erstellen von Views erledigt sprich Viewmodel ruft eine Function der Serviceklasse auf und diese erstellt das View
    2) Messenger => Jede View registriert einen Messenger wenn ich eine View aufrufen möchte dann setzte ich aus dem Viewmodel eine Message ab und die View reagiert => gefällt mir nicht wirklich da ich Code im Codebehind in der View habe und parallel noch MVVM Light reinziehen muss
    3) Erstellen der View direkt aus dem Viewmodel => verletzt den Pattern aber ist relativ einfach zu handhaben.

    Wie würdest du es machen?

    --------------
    Ich bin gerade dabei die Solution in GitHub zu publishen (muss ich morgen fertig machen die Solution aus TFS rauszukriegen ist gar nicht so easy... ), ich glaube es wäre einfacher wenn der Code dort vorliegt als immer die geänderte Solution als ZIP anzuhängen (wenn ich jetzt nicht zu Frech bin und du noch Lust hast zu helfen) ;
    mfG.
    Stephan
    Ich Antworte dir morgen detailierter auf deine Antwort. Aber wegen TFS. Ich hab ein MS Konto. Musst mich also nur zum Projekt einladen.

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

    Hallo und guten morgen

    kaifreeman schrieb:

    Ich denke das die "CurrentUserInfo" Property im ConnectionHolder nichts verloren hat. Ich werde diese dann noch in ein eigenes Singleton packen.

    Richtig, deshalb hatte ich es InstanceHolder benannt. Dort hätte ich sowohl den ConnectionString reingapckt als auch andere Infos welche immer zur Verfügung stehen sollen. In dem Falle der Userinfos und den Rechten des Users hätte ich primitive Datentypen genutzt um keinen Verweis auf das Model haben zu müssen.

    kaifreeman schrieb:

    Mittlerweile ist mir auch klar warum meine Navigationproperties im Viewmodel leer bleiben. Durch das Using Statement kille ich ja immer den aktuellen DBContext.

    Für mich stellt sich daher mittlerweile die Frage ob es nicht besser ist den DBContext als Singleton zu instanzieren so das Programmweit immmer derselbe DBContext genutzt wird.
    Wobei das eigentlich dem Wunsch widerspricht eine minimale Lebenszeit beim DBContext zu haben.

    Gut, dann war meine Vermutung richtig das der Context Diposed wurde.
    Den Context offen zu lassen ist imho eine schlechte Idee. das du ihn brav Disposed ist schon korrekt. Es gibt möglichkeiten den Context von einer BL in die andere "mitzunehmen", was ich auch im HomeStorage bedacht habe. Schau dir das GenericRepository nochmal an. Hier Habe ich Public Property Context() As Object. Der Datentyp ist Object damit ich das EF nicht nach aussen reiche.
    Und dann gibt es einen Konstruktor dem ich einen Context mitgeben kann. Hier merkt sich das Repository dann auch das es im Falle des aufrufs von Dispose nicht Disposen darf da dies die BL dann übernehmen muss.
    So kann ich einen Context mitnehmen falls es notwendig sein sollte. Solte dennoch selten der Fall sein. Denn die BL soll sich ja immer um einen gewissen Teil kümmern, und auch nur so lange sollte man den Context benötigen.


    kaifreeman schrieb:

    Die Function "UpdateUserZoom" ist ein als eine Art Test gedacht um Werte nach einer Änderung zurück in die DB zu schreiben. Später werde ich eine "globale" UpdateUserSettings Function erstellen die beim beenden des Programms die Einstellungen in die DB schreibt.

    Besser immer gleich zurückschreiben, nur als Tipp. Beendet jemand das Programm über den Taskmanager oder schmiert es mal ab wird nichts gepseichert.

    kaifreeman schrieb:

    Zum UoW => es ist wirklich interessant wie viele Meinungen es zu dem Thema gibt, ich habe wie Eingangs erwähnt einen Udemy Kurs von Mosh Hamedami gesehen, dort weißt er explizit auf folgende Umstände hin:
    Repositories sollten nie Objekte vom Typ IQueryable zurückgeben da nach seiner Auffassung ein Fremder Programmierer glaubt er kann damit eine Abfrage machen, Mosh empfiehlt die Rückgabe eines Queryresults in Form einer ObservableCollection(of ...)
    Simpel ausgedrückt, ich möchte alle User meiner Datenbank haben => in der aktuellen Implementierung würde ich es in die Business Logik packen und dann dort abholen, lt. Mosh würde die Business Logik das Repository Fragen und das Repository macht die Query und gibt das Result zurück.

    Das kann ich auf einer Seite unterstützen auf der anderen wieder nicht. Es kommt immer darauf an. Habe ich als Datengrundlage eine XML trifft dies zu.
    Im Falle von EF wieder nicht, da hier der User ja tatsächlich die Abfrage absendet. Also kann der fremde Prorammierer tatsächlich eine Abfrage absenden. Das selbe gilt mit einer Rest API als Datengrundlage. Diese unterstützt auch IQueryable. Ef Core ist sogar im UnitOfWork Stil im programmiert worden!
    Solange du dein Query zusammenbaust wird ja keine Abfrage an die DB gesendet. Erst bei .ToList, FirstOrDefault, Single, Any usw. wird tasächlich erst die Abfrage an die DB gemacht. Also geschiet dies WIRKLICH erst in der BL. Das ist die Magie die du hier hast.

    Nach dem Ansatz von Mosh Hamedami würde im Falle von EF als Context das Repository ja lediglich "durchreichen". Was keinen sinn hat und völlig unnötig wäre.
    Beispiel: Ich suche alle Kunden mit "müller" im Namen welche in 2700 Wohnen. Da hätte ich im Repository eine Methode GetCustomersByContainsNameAndZipCode. Du kannst dir sicher vorstellen wieviele Methode du dann haben wirst. Weiters hast du dann das Problem das du auch noch immer zu viele Daten abrufst weil du hier nicht mal enscheiden kannst welche Spalten du brauchst. Sehr schlecht für die Performance.

    Durch das IQueryable bist du so flexibel da du auch in Sachen performance gut unterwegs bist. Ich denke das sich hier einiges getan hat auf das Mosh Hamedami nicht einging.

    kaifreeman schrieb:

    Fürs erstellen einer neuen View gibt es ja mehrere Konzepte

    Es kommt für mich eindeutig nur Punkt 1 in frage. Punkt 3 geht gar nicht.
    Ich weis nicht wie die Services in MVVM Light funktionieren und wie "gut" oder "schlecht" das geht. Ich kann nur von meinem "Framework" sprechen, da ist es nicht mehr zum Tippen als würde ich die View ind ViewModel holen.

    So kann ICH z.b. ein neues Fenster als Dialog öffnen und dabei sogar ein anderes Fenster als Owner übergeben (ich weis nicht ob MVVM Light das mit dem Owner auch unterstützt)

    VB.NET-Quellcode

    1. Dim diaServ = ServiceContainer.GetService(Of IDialogWindowService)
    2. If diaServ.ShowDialog("NeuerDialog",New testVm,Me) = True Then 'Me ist hier de Owner, eine eigene Logik im Windows selbst sucht nach dem richtigen Window anhand des ViewModel (ME)
    3. End If


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

    Hallo Sascha,

    sry hatte gestern keine Zeit mehr zu antworten.
    Ich hab das Repository jetzt ins Azure DevOps geladen wenn du mir dein MS Konto zukommen lässt lade ich dich zum Repo ein. Bis dato hatte ich ja alles auf meinem lokalen TFS aber mittlerweile ist das echt nicht mehr notwendig.

    Ich werde jetzt sukzessive das Programm umbauen und implementieren, ich würde diesen Thread weiterhin nutzen dann haben andere Interessierte eventuell auch die Historie.

    Nofear23m schrieb:

    Durch das IQueryable bist du so flexibel da du auch in Sachen performance gut unterwegs bist. Ich denke das sich hier einiges getan hat auf das Mosh Hamedami nicht einging.


    Ich kann leider hier den Udemy Kurs nicht präsentieren, es ging in diesem ja primär um Entity Framework und Repositories wurden nur als Architektur erwähnt. Die Implementierung kam mir auch etwas seltsam vor wie du sagt man müsste für jede mögliche Abfrage eine eigene Function haben das ging in die 1000e bei einem umfangreichen Projekt. DIe Lösung mit den IQueryables ist definitiv besser zu handhaben und flexibler. Gerade im ERP Bereich für das das Projekt ja gedacht ist ein absolutes muss.

    Nofear23m schrieb:

    Es kommt für mich eindeutig nur Punkt 1 in frage. Punkt 3 geht gar nicht.
    Ich weis nicht wie die Services in MVVM Light funktionieren und wie "gut" oder "schlecht" das geht. Ich kann nur von meinem "Framework" sprechen, da ist es nicht mehr zum Tippen als würde ich die View ind ViewModel holen.

    Ich werde mich mal mit dem MVVM Light Framework auseinandersetzen, aktuell habe ich einen FrameNavigationService am laufen der mit Pages arbeitet, das klappt eigentlich schon perfekt ich muss nur noch prüfen ob das auf Dauer praktikabel ist.
    mfG.
    Stephan
    Hallo, hey kein Thema. Wenn du Zeit hast hast du Zeit und wenn nicht dann nicht.

    kaifreeman schrieb:

    Ich hab das Repository jetzt ins Azure DevOps geladen wenn du mir dein MS Konto zukommen lässt lade ich dich zum Repo ein. Bis dato hatte ich ja alles auf meinem lokalen TFS aber mittlerweile ist das echt nicht mehr notwendig.

    Ist öffentlich in meinem Profil.

    kaifreeman schrieb:

    Ich werde jetzt sukzessive das Programm umbauen und implementieren, ich würde diesen Thread weiterhin nutzen dann haben andere Interessierte eventuell auch die Historie.

    Auf jeden Fall, ich finde auch das wir hier alle Updates Posten sollten damit man es nachvollziehen kann. Nur wir sparen und das ständige hochladen. Und Marcus ist sicher auch damit einverstanden das wir seinen speicher nicht zumüllen. *gg*

    kaifreeman schrieb:

    Die Implementierung kam mir auch etwas seltsam vor wie du sagt man müsste für jede mögliche Abfrage eine eigene Function haben das ging in die 1000e bei einem umfangreichen Projekt. DIe Lösung mit den IQueryables ist definitiv besser zu handhaben und flexibler.

    Ja, machen aber leider viele so. OK, wenn von vornherein die warscheinlichkeit hoch ist das ich die Datenhaltung vermutlich später auf etwas umstelle wo ich IQueryable nicht nutzen kann ist das noch in Ordnung, aber wozu? Viele verschiedene Technologien wie APIs oder O/R Mapper liefern ein IQueryable, also warum nutze ich es nicht. Finde ich einfach unnötige Arbeit für alles was ich an CRUD machen möchte zig Methoden zu erstellen. Ausserdem benötigt man dann wirklich für jede Modelklasse ein Repository und kann hier nicht richtig generisch Arbeiten. Und im Endeffekt reiche ich fast immer nur durch. Aber Toll!! Ich hab ne eigene Schicht erzeugt :thumbsup:

    Naja, aber jetzt sehen wir mal das wir dein aktuelles "Testprojekt" säubern und dann gehts erst weiter. Bez. MVVM Light muss ich mioch auf dich verlassen, ich will mich damit ehrlich gesagt nicht auseinandersetzen. Ich habe mein eigenes Ding "erstellt" und komme damit super zurecht, ich den Code kann ich wenigstens jederzeit bearbeiten wenn mir was nicht passt oder was nicht klappt, das kann ich mit einem Framework nicht, da muss ich auf ein Update warten.

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