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 Stephan

    Da ich bis dato keine DevOps Einadung erhalten habe wollte ich mal nachfragen. Lebt das Projekt noch?
    Ansonsten könnten wir es ja als "Erledigt" markieren.

    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,

    schon länger her das ich jetzt geschrieben habe, aber ich bin beim System ein großes Stück weitergekommen.
    Habe jetzt die Layertrennung ganz gut hingekriegt und auch das Laden der Views läuft ohne den MVVM Pattern zu verletzen.
    Jetzt bin ich aber wieder an dem Punkt wo mir die Layertrennung große Probleme bereitet.
    Es geht eigentlich um eine Standardoperation, nämlich mal wieder einer NavigationProperty ein neues Element hinzuzufügen, die View updaten und das Model bzw. die DB aktualisieren.

    Ich habe die Entität UsergroupRights als Beispiel genommen.
    Ich möchte dieser Entität weitere Berechtigungen geben folgende Ansätze habe ich versucht:

    1. Das hinzufügen eines Benutzerrechtes über meine Business Logik (Klasse UsergroupBL)

    VB.NET-Quellcode

    1. Public Function AddUserGroupRight(_UserGroupId As Guid, _GroupRightsToAdd As IList(Of AuthorizationItem)) As Boolean
    2. If _UserGroupId = Guid.Empty OrElse _GroupRightsToAdd Is Nothing OrElse _GroupRightsToAdd.Count = 0 Then Return False
    3. 'Using Worker As GenericRepository(Of UserGroup) = _Repository
    4. Dim query = _Repository.FindBy(Function(x) x.Id = _UserGroupId)
    5. query = query.Include("NvUserGroupRights")
    6. query = _Repository.SetTracking(True, query)
    7. Dim vUserGroup As UserGroup = query.Single
    8. Dim vSavecounter As Integer = 0
    9. For Each vItem As AuthorizationItem In _GroupRightsToAdd
    10. If vUserGroup.NvUserGroupRights.Where(Function(x) x.Authorization.ToLower = vItem.Key.ToLower).Count = 0 Then
    11. vSavecounter += 1
    12. vUserGroup.NvUserGroupRights.Add(New UserGroupRight With {.Authorization = vItem.Key.ToLower, .GroupId = vUserGroup.Id})
    13. End If
    14. Next
    15. If _Repository.Save = vSavecounter Then
    16. Return True
    17. Else
    18. Return False
    19. End If
    20. End Function

    Das funktioniert aber aktualisiert mein Viewmodel nicht.

    2. Weg hinzufügen über das Viewmodel: UserGroupAddEditVM

    VB.NET-Quellcode

    1. Private Async Sub AuthorizationsAdd(SelectedItems As Object)
    2. Debug.Print(_EntityViewmodel.NvUserGroupRights.Count.ToString)
    3. 'The SelectedItems is type of object because we receive a SelectedItemsCollection from the listview
    4. Dim vHelper As IList = CType(SelectedItems, IList)
    5. If vHelper Is Nothing OrElse vHelper.Count = 0 Then Return
    6. Dim vSelectedItemsList As IList(Of AuthorizationItem) = vHelper.Cast(Of AuthorizationItem).ToList
    7. Dim vStr As New StringBuilder("Sollen folgende Berechtigungen hinzugefügt werden?")
    8. vStr.AppendLine()
    9. For Each vItem As AuthorizationItem In vSelectedItemsList
    10. vStr.AppendLine(vItem.Name)
    11. Next
    12. Dim Result As MessageDialogResult = Await dialogCoordinator.ShowMessageAsync(Me, "Berechtigung hinzufügen", vStr.ToString, MessageDialogStyle.AffirmativeAndNegative)
    13. If Result = MessageDialogResult.Affirmative Then
    14. Dim vSavecounter As Integer = 0
    15. For Each vItem As AuthorizationItem In vSelectedItemsList
    16. If _EntityViewmodel.NvUserGroupRights.Where(Function(x) x.Authorization.ToLower = vItem.Key.ToLower).Count = 0 Then
    17. vSavecounter += 1
    18. Dim bla As New UserGroupRight With {.Authorization = vItem.Key.ToLower, .GroupId = _EntityViewmodel.Id}
    19. _EntityViewmodel.NvUserGroupRights.Add(New UserGroupRightVM(bla))
    20. End If
    21. Next
    22. End If
    23. End Sub


    Diese Vorgehensweise aktualisiert meine View interessiert aber mal wieder das Model überhaupt nicht.

    Folgende Vorgehensweise wurde gewählt:
    Es gibt eine Übersicht der Usergroups => View UsergroupsOverview dort wird eine Benutzergruppe ausgewälhlt und ein entsprechendes Edit Command ausgeführt.
    Dieses Command nutzt meinen FrameNavigationService um ein neues Fenster AddEdit zu öffnen mit einem entsprechenden Viewmodel dahinter. Parallel wird die ID der zu editierenden Benutzergruppe übergeben und mit folgender Function zu seinem Entität Viewmodel gemacht:

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Checks if the form is called for an add or edit if edit searches the correct usergroup and Sets it to the _EntityViewmodel
    3. ''' </summary>
    4. ''' <returns></returns>
    5. Public Overrides Function SetRealObject() As Boolean
    6. If ItemGuid = Guid.Empty Then
    7. 'Add mode:
    8. _EntityViewmodel = New UserGroupVM(New UserGroup)
    9. Else
    10. 'Edit mode:
    11. Dim query = UoW.FindBy(Function(x) x.Id = ItemGuid).Include("NvUserGroupRights")
    12. query = UoW.SetTracking(True, query)
    13. Dim ItemToEdit = query.Single
    14. UoW.Attach(ItemToEdit)
    15. UoW.Edit(ItemToEdit)
    16. _EntityViewmodel = New UserGroupVM(ItemToEdit)
    17. For Each Item As UserGroupRight In ItemToEdit.NvUserGroupRights
    18. _EntityViewmodel.NvUserGroupRights.Add(New UserGroupRightVM(Item))
    19. Next
    20. End If
    21. RaisePropertyChanged("_EntityViewmodel")
    22. If DisplayMode = DisplayType.Edit Then _EntityViewmodel.BeginEdit()
    23. Return True
    24. End Function


    Hinweis die Zeilen UoW.Attach und .Edit sind mehr aus der Verzweiflung entstanden das Update doch noch hinzubekommen....

    Achso und der Konstruktor macht folgendes:

    VB.NET-Quellcode

    1. Private ReadOnly UoW As GenericRepository(Of UserGroup)
    2. Sub New()
    3. UoW = New GenericRepository(Of UserGroup)
    4. AvailableAuthorizations = New ListCollectionView(AuthorizationRepositoryCls.Instance.Authorizations)
    5. End Sub

    Beim erstellen des Viewmodels wird noch mal ein GenericRepository erzeugt das "am leben" bleibt bis das Viewmodel geschlossen wird (Cleanup bzw. Dispose ist noch nicht implementiert).

    Im Thread hattest du ja geschrieben das der changetracker Änderungen am Modell erkennt solange der DB Context nicht disposed wird.
    Es wird ja zwar im GenericRepository ein neuer DBContext erzeugt aber dieser bleibt über die Lifetime ja aktiv trotzdem macht der Changetracker nichts.
    Natürlich habe ich mir gedacht ich könnte ja die Benutzergruppenrechte an den context attachen was aber wiederum auch nicht geht weil das GenericRepository vom Typ (of UserGroup) und nocht (of UserGroupRight) ist.

    Ich könnte mir jetzt zwar denken das ich mir noch ein Repository ableite und das dann dort erledige aber es kann doch nicht Sinn der Sache sein für eine simple Operation gefühlt hundert Klassen zu benötigen.....
    Daher vermute ich mal wieder ich bin einfach zu dämlich um das zu begreifen.... :(

    Wäre echt super wenn du dir mal das Repository anschauen könntest.





    ----- Edit:
    Da hat sich das wohl überschnitten.
    Mich wundert das du noch keine Einladung hast lt. meinem DevOps bist du Teil des Teams....
    Ich hab dir jetzt nochmals eine Einladung geschickt:
    dev.azure.com/myareaat/MyERP2
    mfG.
    Stephan

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

    Hallo

    Komisch, habe keine Einladung erhalten. Jetzt habe ichs aber Klonen können.
    Hast du auch eine serverlist.xml für mich?

    Sonst klappt es nicht.

    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,

    ich werd dich nochmal zum Team hinzufügen.

    Die serverlist.xml liegt im MyERP2.BL unter Usermanagement, diese musst du aktuell noch per Hand in %appdata%/local/MyERP2 schupfen. Hab hier noch keine Prüfung eingebaut.
    mfG.
    Stephan

    kaifreeman schrieb:

    ich werd dich nochmal zum Team hinzufügen.

    Nene, passt schon, bin eh im Team.

    kaifreeman schrieb:

    Hab hier noch keine Prüfung eingebaut.

    Naja, ne Prüfung ob sie existiert haste ja eh.

    Nur hatte ich keine Vorlage wie die XML aussehen muss. Habe aber auch nur im VM gesucht da dort die Prüfung und alles stattfindet. Gehört ja eigendlich eh in die BL. Solltest du noch verschieben. =O

    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

    Einfach damit ich am aktuellen Stand bin und weis WO du nun bist und was als nächstes funktionieren soll und vorallem was bereits funktionieren sollte.

    Login klappt bei mir nicht, ist das richtig? Habe in der DB den Administrator in sa geändert da ich mich sonst nicht anmelden kann.
    Es scheint du hast den Login deines Programms mit dem Login am SQL Server gekommpelt. Gibts dafür einen Grund? Irgendwie kommts mir da ein wenig hoch weil ich mich frage wozu.
    EF Logt sich ein, das ist ja unabhängig von deiner App. Das Passwort sollte in deiner DB stehen.



    Obwohl das ein merkwürdiges konstrukt ist:

    VB.NET-Quellcode

    1. If vCUser Is Nothing Then Throw New KeyNotFoundException("Benutzername zur Rechtverwaltung konnte nicht gefunden werden")

    Das kann NIE ausgeführt werden. .Single wirft ne Exception wenn Keiner oder Mehrere Datensätze zurückkommen.
    Du müsstest SingleOrDefault schreiben.

    Beschreib mal bitte kurz was funktionieren soll und was wo passieren soll, vieleicht mit ein paar Screenshots und was noch nicht funzt.
    So kann ich mir mal ein Bild machen ohne jetzt das ganze Projekt zu durchforsten.

    Edit: OK, den Fehler habe ich behoben, aber dennoch. Beschreibe mal so gut es geht, denn nach dem Login geht einfach nur ein Schwarzes Fenster auf. sonst nix. :huh:

    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“ ()

    Hallo Sascha,

    Nofear23m schrieb:

    Nur hatte ich keine Vorlage wie die XML aussehen muss. Habe aber auch nur im VM gesucht da dort die Prüfung und alles stattfindet. Gehört ja eigendlich eh in die BL. Solltest du noch verschieben.

    Aktuell wird die Serverliste noch im Viewmodel geladen haste recht hat dort eigentlich nix verloren gehört in die Businesslogik werde ich beim nächsten Push mitmachen. => Task 21

    Nofear23m schrieb:

    Es scheint du hast den Login deines Programms mit dem Login am SQL Server gekommpelt

    Richtig erkannt das Login Management übernimmt hier der SQL Server. Meine Überlegung ist folgende gewesen. Das System ist ausschließlich dafür gedacht mit einem SQL Server zu arbeiten, der SQL Server hat eine integrierte Benutzerverwaltung ich kann dort ganz gut alle Rechte der Benutzer steuern
    ohne das ich dem Programm einen "Masterzugang" geben muss für jeden User und dann über irgendwelche internen Tabellenberechtigungen die Benutzerverwaltung vom SQL Server ausheble.
    Vermutlich musstest du den "sa" Benutzer verwenden weil am Server kein "Administrator" Benutzer angelegt ist. Ich benutze ungern den SA auf meinem SQL Server sondern verwende für jedes Projekt einen eigenen Administrationsaccount.

    Nofear23m schrieb:

    Das kann NIE ausgeführt werden. .Single wirft ne Exception wenn Keiner oder Mehrere Datensätze zurückkommen.
    Du müsstest SingleOrDefault schreiben.

    Zuvor hatte ich auch ein SingleorDefault geschrieben habe leider erst gestern gesehen das die Execption geworfen wird daher sind noch einige "fraktale" im Code die definitiv nicht ausgeführt werden. Im aktuellen Push entfernt.

    Nofear23m schrieb:

    denn nach dem Login geht einfach nur ein Schwarzes Fenster auf

    Das klingt jetzt irgendwie eigenartig. Nach dem Login sollte eigentlich das Mainwindow aufgerufen werden:

    Das klingt ganz nach einem Zoom Problem, wenn der Zoom widererwarten 0 zurückgibt dann erhält man ein schwarzes Fenster.

    Das würde jetzt auch erklären warum du dich nur mit dem User SA einloggen konntest.
    Eigentlich sollte der DBContext folgenden User seeden:

    VB.NET-Quellcode

    1. //Seeding
    2. //Add User Administrator
    3. Guid UserId = Guid.NewGuid();
    4. modelBuilder.Entity<Model.MyERP2Model.User>().HasData(new Model.MyERP2Model.User {Id=UserId, Username = "Administrator", CreatedBy = "Seed", CreationTimestamp = DateTime.Now,Zoom=1 });


    Damit wird ein Standard User Administrator mit dem Zoom 1 angelegt. Bitte prüfe ob in der dbo.Users Tabelle der Eintrag geseedet wurde.

    Es wäre natürlich schlau von mir gewesen zu erwähnen das ein SQL-Server User Administrator angelegt werden sollte der der auch auf die DB zugreifen darf. Mein Fehler sry.

    -----------------
    Aktuell liegt mein Problem in der Benutzergruppenverwaltung begraben. (Erreichbar über Menü Links: Administration -> Benutzergruppen) (Hinweis: Wenn hier die Benutzergruppe Administratoren fehlt dann hat der Seed nicht richtig funktioniert.)
    Die Administratore dann doppelt klicken oder Links oben "bearbeiten"
    Dann erscheint die View UsergroupAddEditFrm welche auch das Viewmodel UsergroupAddEditVM aufruft und daran bindet.

    Beim Command CmdAuthorizationsAdd in der Function AuthorizationsAdd(p) füge ich der Benutzergruppe ein oder mehrere Rechte hinzu.

    VB.NET-Quellcode

    1. Private Async Sub AuthorizationsAdd(SelectedItems As Object)
    2. Debug.Print(_EntityViewmodel.NvUserGroupRights.Count.ToString)
    3. 'The SelectedItems is type of object because we receive a SelectedItemsCollection from the listview
    4. Dim vHelper As IList = CType(SelectedItems, IList)
    5. If vHelper Is Nothing OrElse vHelper.Count = 0 Then Return
    6. Dim vSelectedItemsList As IList(Of AuthorizationItem) = vHelper.Cast(Of AuthorizationItem).ToList
    7. Dim vStr As New StringBuilder("Sollen folgende Berechtigungen hinzugefügt werden?")
    8. vStr.AppendLine()
    9. For Each vItem As AuthorizationItem In vSelectedItemsList
    10. vStr.AppendLine(vItem.Name)
    11. Next
    12. Dim Result As MessageDialogResult = Await dialogCoordinator.ShowMessageAsync(Me, "Berechtigung hinzufügen", vStr.ToString, MessageDialogStyle.AffirmativeAndNegative)
    13. If Result = MessageDialogResult.Affirmative Then
    14. Dim vSavecounter As Integer = 0
    15. For Each vItem As AuthorizationItem In vSelectedItemsList
    16. If _EntityViewmodel.NvUserGroupRights.Where(Function(x) x.Authorization.ToLower = vItem.Key.ToLower).Count = 0 Then
    17. vSavecounter += 1
    18. Dim NewUserGroupRight As New UserGroupRight With {.Authorization = vItem.Key.ToLower, .GroupId = _EntityViewmodel.Id}
    19. UoWGroupRights.Attach(NewUserGroupRight)
    20. _EntityViewmodel.NvUserGroupRights.Add(New UserGroupRightVM(NewUserGroupRight))
    21. NewUserGroupRight = Nothing
    22. End If
    23. Next
    24. End If
    25. End Sub


    Gestern nacht habe ich das Problem noch gelöst aber ich glaube das es nicht richtig ist es so zu tun.
    1. Eigentlich müsste das hinzufügen der Authorization in BL Layer erfolgen nicht im Viewmodel aber der BL kennt ja das Viewmodel nicht somit bekomme ich ja nur "Model Objekte" rein und raus aber keine Viewmodels
    2. Wenn ich die Arbeit im BL erledige erhalte ich keine Rückmeldung an die View, ich kann auch vom Viewmodel keinen DBContext übergeben weil dieser ja im Konstruktor "Friend" liegt....

    wie gesagt der obige Code funzt aber ich glaube das ich mich da in eine falsche Richtung bewege.

    -------------- EDIT ----------------------
    Ich glaube ich habe jetzt eine bessere Lösung entdeckt:

    in der Businesslogik für Benutzergruppen:

    VB.NET-Quellcode

    1. Public Function AddUserGroupRights(_UserGroupId As Guid, _GroupRightsToAdd As IList(Of AuthorizationItem)) As List(Of UserGroupRight)
    2. Dim vInternalList As New List(Of UserGroupRight)
    3. If _UserGroupId = Guid.Empty OrElse _GroupRightsToAdd Is Nothing OrElse _GroupRightsToAdd.Count = 0 Then Return Nothing
    4. 'Using Worker As GenericRepository(Of UserGroup) = _Repository
    5. Dim query = _Repository.FindBy(Function(x) x.Id = _UserGroupId)
    6. query = query.Include("NvUserGroupRights")
    7. query = _Repository.SetTracking(True, query)
    8. Dim vUserGroup As UserGroup = query.Single
    9. _Repository.Attach(vUserGroup)
    10. Dim vSavecounter As Integer = 0
    11. For Each vItem As AuthorizationItem In _GroupRightsToAdd
    12. If vUserGroup.NvUserGroupRights.Where(Function(x) x.Authorization.ToLower = vItem.Key.ToLower).Count = 0 Then
    13. vSavecounter += 1
    14. Dim vNewItem As New UserGroupRight With {.Authorization = vItem.Key.ToLower, .GroupId = vUserGroup.Id}
    15. vInternalList.Add(vNewItem)
    16. vUserGroup.NvUserGroupRights.Add(vNewItem)
    17. vNewItem = Nothing
    18. End If
    19. Next
    20. If Not _Repository.Save = vSavecounter Then Throw New Exception("Nicht alle Benutzerrechte wurden gespeichert")
    21. If vInternalList Is Nothing OrElse vInternalList.Count = 0 Then
    22. Return Nothing
    23. Else
    24. Return vInternalList
    25. End If
    26. End Function


    im Viewmodel:

    VB.NET-Quellcode

    1. Private Async Sub AuthorizationsAdd(SelectedItems As Object)
    2. Debug.Print(_EntityViewmodel.NvUserGroupRights.Count.ToString)
    3. 'The SelectedItems is type of object because we receive a SelectedItemsCollection from the listview
    4. Dim vHelper As IList = CType(SelectedItems, IList)
    5. If vHelper Is Nothing OrElse vHelper.Count = 0 Then Return
    6. Dim vSelectedItemsList As IList(Of AuthorizationItem) = vHelper.Cast(Of AuthorizationItem).ToList
    7. Dim vStr As New StringBuilder("Sollen folgende Berechtigungen hinzugefügt werden?")
    8. vStr.AppendLine()
    9. For Each vItem As AuthorizationItem In vSelectedItemsList
    10. vStr.AppendLine(vItem.Name)
    11. Next
    12. Dim Result As MessageDialogResult = Await dialogCoordinator.ShowMessageAsync(Me, "Berechtigung hinzufügen", vStr.ToString, MessageDialogStyle.AffirmativeAndNegative)
    13. If Result = MessageDialogResult.Affirmative Then
    14. Dim vItemsToAdd As List(Of UserGroupRight)
    15. Using BL As New UsergroupBl(UoW)
    16. vItemsToAdd = BL.AddUserGroupRights(_EntityViewmodel.Id, vSelectedItemsList)
    17. If Not vItemsToAdd Is Nothing Then
    18. For Each vitem In vItemsToAdd
    19. _EntityViewmodel.NvUserGroupRights.Add(New UserGroupRightVM(vitem))
    20. Next
    21. End If
    22. End Using
    23. End If
    24. End Sub


    View wird aktualisiert, speichern erfolgt auch in der DB ich glaube das sollte der bessere Weg sein, bitte um Experten Meinung :D
    mfG.
    Stephan

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

    kaifreeman schrieb:

    Richtig erkannt das Login Management übernimmt hier der SQL Server. Meine Überlegung ist folgende gewesen. Das System ist ausschließlich dafür gedacht mit einem SQL Server zu arbeiten, der SQL Server hat eine integrierte Benutzerverwaltung ich kann dort ganz gut alle Rechte der Benutzer steuern
    ohne das ich dem Programm einen "Masterzugang" geben muss für jeden User und dann über irgendwelche internen Tabellenberechtigungen die Benutzerverwaltung vom SQL Server ausheble.

    Imho eine eher schlechte Idee. Wie machst du dann ne Schemamigration?
    Wenn der User nicht die Rechte hat Tabellen zu ändern oder vieleicht neue angzulegen schlägt dies brutal fehl.

    Scenario: Die Sekretärin kommt vor dir (admin) ins Büro und startet den Rechner - Oh es gibt ein Update, na das ziehen wir doch gleich. App startet, EF will migrieren - !ERROR!
    Ups, tja, die Dame hat nicht die Rechte nd schon kann sie nicht mehr arbeiten. Ausserdem ist es eine schlechte Sache User an zwei stellen aktuell zu halten. 1x in der DB und 1x am SQL Server oder?
    Wie kann den der User sein Passwort ändern? Gar nicht oder? Muss der Admin machen? Nicht gut.
    Lege am SQL Server einen User EF Core an der die notwendigen Rechte besitzt. Mit diesem User Verbindet sich deine App und gut ists.
    Alles andere regelst du über deine App bzw. die DB. Also Passwörter der User verschlüsselt in die DB und fertig.

    Besser oder?

    kaifreeman schrieb:

    Das klingt jetzt irgendwie eigenartig. Nach dem Login sollte eigentlich das Mainwindow aufgerufen werden:

    Ich habe nun die DB neu erstellt, jetzt haut es hin. Hier hattest du auch nocht einen Fehler, es wurde NIE CreateDbIfNotExist aufgerufen, somit nie die DB erstellt.
    Habe ich nun in LoginBl eingefügt:

    VB.NET-Quellcode

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


    kaifreeman schrieb:

    Das klingt ganz nach einem Zoom Problem, wenn der Zoom widererwarten 0 zurückgibt dann erhält man ein schwarzes Fenster.

    Uiuiui

    Was ist das denn?

    VB.NET-Quellcode

    1. Public ReadOnly Property LoginZoom As Double
    2. Get
    3. 'Set a Screenresolution based Zoomfactor:
    4. If Windows.SystemParameters.PrimaryScreenWidth > 1024 Then
    5. Return 1.2
    6. Else
    7. Return 1
    8. End If
    9. End Get
    10. End Property


    Eine abhängigkeit die nicht sein muss. Wenn dann mach das über die App in den InstanceHolder oder noch besser, gestallte die View richtig so das dies nicht notwendig ist. Stichwort ViewBox.

    kaifreeman schrieb:

    Aktuell liegt mein Problem in der Benutzergruppenverwaltung begraben.

    OK, das schau ich mir an sobald ich hier mal durchblicke ;)

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

    kaifreeman schrieb:

    View wird aktualisiert, speichern erfolgt auch in der DB ich glaube das sollte der bessere Weg sein, bitte um Experten Meinung

    Vollkommen richtig. Die zweite Veriante ist gut.

    Es gilt immer. DB aktualisieren und im View (ViewModel) nachreichen.
    Also immer syncron halten.

    Dafür gibt es zwei möglichkeiten. Ich speichere in die DB und lade das ViewModel neu. So das z.b. Listen neu abgerufen werden
    - oder -
    Ich speichere in die DB, merke mir was gespeichert wird und aktualisieren nur das im ViewModel.

    Letzteres ist performanter, aber auch mehr arbeit. Auch muss man aufpassen das man nicht etwas im ViewModel aktuelisiert was vieleicht beim speichern in die DB fehlgeschlagen ist, sonst denkt der User das alles in Ordnung ist weil es ja so angezeigt wird, es aber nicht ist, und beim nächsten mal wenn er das Fenster öffnet ist es nicht da weil ja nicht korrekt gespiechert wurde. Also muss hier etwas mehr aufgepasst werden.

    Grüße
    Sascha

    PS: Ich habe kleine änderungen gemacht die ich schnell noch pushe.
    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,

    danke für deinen Input, hab jetzt mal alles wieder gemerged und gepusht.
    Unit Test habe ich angepasst da sich die UserGroupAddRight Methode geändert hat.

    Habe inzwischen weitergearbeitet und das "delete" für die Benutzergruppen Rechte implementiert, allerdings ist mir hier ein unlustiger Umstand aufgefallen.
    Anscheinend ist es nicht möglich beim Include einer Navigation Property eine Where Clause bzw. einen Vorfilter dazuzupacken.

    VB.NET-Quellcode

    1. 'Beispiel zum inkludieren einer Navigation Property:
    2. Dim query = UoW.FindBy(Function(x) x.Id = ItemGuid).Include("NvUserGroupRights")
    3. 'Versuch mit nachfolgender Where:
    4. Dim query = UoW.FindBy(Function(x) x.Id = ItemGuid).Include("NvUserGroupRights").Where(Function(x) x.NvUserGroupRights.Any(Function(z) z.DeletedFlag = False))
    5. 'Versuch mit Where im Include:
    6. Dim query = UoW.FindBy(Function(x) x.Id = ItemGuid).Include(Function(y) y.NvUserGroupRights.Where(Function(z) z.DeletedFlag = False))
    7. 'Versuch mit Select
    8. Dim query = UoW.FindBy(Function(x) x.Id = ItemGuid).Include(Function(y) y.NvUserGroupRights.Select(Function(z) z.DeletedFlag = False))


    Ich kann mich erinnern das du erwähnt hast das Navigation Properties eigentlich nicht wirklich eine gute Idee sind.
    Ich bin da glaube ich an dem Punkt angelegt dir zuzustimmen.
    Ob ich jetzt in meinem Viewmodel eine Navigation Property habe oder eine 2. Property im Viewmodel habe die mir die Benutzerrechte hält ändert eigentlich nicht wirklich was hat aber den Vorteil
    das ich ohne das ganze include gedönse auskommen würde, sehe ich das korrekt?

    --------
    Zur LoginLogik:

    Nofear23m schrieb:

    Wenn der User nicht die Rechte hat Tabellen zu ändern oder vieleicht neue angzulegen schlägt dies brutal fehl.


    Dein Beispiel ist nicht von der Hand zuweisen auch das Thema der Passwortänderung ist ebenfalls ein Problem.
    Ich werde das Login nochmal umstellen und mit einem globalen MyERP2 User arbeiten aber:
    Wo sollte man das Passwort dieses Zentralen Users speichern? Ich meine wenn das einer bekommt kann er am Server ziemlich alles, eigentlich ein Sicherheitsrisiko?
    Was passiert wenn sich das zentrale Passwort ändert? Das muss alles noch durchdacht werden....
    mfG.
    Stephan

    kaifreeman schrieb:

    Ob ich jetzt in meinem Viewmodel eine Navigation Property habe oder eine 2. Property im Viewmodel habe die mir die Benutzerrechte hält ändert eigentlich nicht wirklich was hat aber den Vorteil
    das ich ohne das ganze include gedönse auskommen würde, sehe ich das korrekt?

    Ne, Das Include sparst du dir nicht, du musst ja trotzdem die Daten abrufen.

    kaifreeman schrieb:

    Wo sollte man das Passwort dieses Zentralen Users speichern?

    Ich mache das in meinen Projekten so das ich ne XML habe wo die Connectiondaten gespeichert sind. So gut wie alles im Klartext bis auf das Kennwort. Das wird verschlüsselt abgespeichert. Fertig.
    Sicher, ist zu knacken aber das ist es mit "deinem" weg auch.

    kaifreeman schrieb:

    Was passiert wenn sich das zentrale Passwort ändert?

    Warum soll sich das ändern? Den User für EF lege ich als Admin ja 1x an und habe die Kontrolle. Wenn ich definiere das das Kennwort nicht abläuft ist dem so.

    Was dein Problem betrifft.
    So ganz check ichs nicht. Warum ein FindBy UND ein WHERE???

    Ich hab das mal getestet, bei mir funzt das.
    Habe einen Test geschrieben:

    VB.NET-Quellcode

    1. <TestMethod> <TestCategory("BL.UserGroup")> Public Sub TestQuery()
    2. Using UoW As New GenericRepository(Of UserGroup)(_db)
    3. Dim idForSearch As Guid = _db.UserGroups.First.Id
    4. Dim query = UoW.FindBy(Function(x) x.Id = idForSearch AndAlso x.DeletedFlag = False).Include(Function(i) i.NvUserGroupRights)
    5. Assert.IsNotNull(query.First.NvUserGroupRights)
    6. End Using
    7. End Sub



    Der generiert folgenden SQL:

    SQL-Abfrage

    1. exec sp_executesql N'SELECT [x.NvUserGroupRights].[Id], [x.NvUserGroupRights].[Authorization], [x.NvUserGroupRights].[CreatedBy], [x.NvUserGroupRights].[CreationTimestamp], [x.NvUserGroupRights].[DeletedFlag], [x.NvUserGroupRights].[DeletedTimestamp], [x.NvUserGroupRights].[GroupId], [x.NvUserGroupRights].[LastUpdateBy], [x.NvUserGroupRights].[LastUpdateTimestamp]
    2. FROM [UserGroupRights] AS [x.NvUserGroupRights]
    3. INNER JOIN (
    4. SELECT TOP(1) [x0].[Id]
    5. FROM [UserGroups] AS [x0]
    6. WHERE ([x0].[Id] = @__$VB$Local_idForSearch_0) AND ([x0].[DeletedFlag] = 0)
    7. ORDER BY [x0].[Id]
    8. ) AS [t] ON [x.NvUserGroupRights].[GroupId] = [t].[Id]
    9. ORDER BY [t].[Id]',N'@__$VB$Local_idForSearch_0 uniqueidentifier',@__$VB$Local_idForSearch_0='F63E0F50-DE97-4ECF-A0AE-FDBDE590DA6E'


    Mal abgesehen davon: Was um gottes willen macht das Repository im ViewModel =O 8|
    Das ViewModel sollte ja gar keinen Verweis auf das Repository haben. Das soll ja die Businesslogik machen!!!!!

    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,

    Nofear23m schrieb:

    Ne, Das Include sparst du dir nicht, du musst ja trotzdem die Daten abrufen.


    Das ich Daten brauche ist klar aber ich frage mich wirklich ob es einen Mehrwert darstellt im Viewmodel die Relation abzubilden.
    Aktuell ist ja im VM die Navigation Property hinterlegt, aber eigentlich mach es keinen Unterschied ob ich einen Collection mit den Benutzergruppen und eine separate Collection mit den dazugehörigen Rechten habe, nur eben mit dem Vorteil das ich das dann beim FindBy filtern kann.

    es geht ja um die Userberechtigungen. Ich habe ja 1:n von Usergroup auf UsergroupRight und in der UsergroupRight können natürlich Rechte von der Benutzergruppe gelöscht werden.
    Daher muss ich die Navigationproperty beim Laden ja nach Deleted Flag filtern und genau das klappt eben nicht.
    wenn ich im Findby nach dem DeletedFlag frage trifft es ja nur die Benutzergruppen aber nicht die Berechtigungen.

    Nofear23m schrieb:

    Mal abgesehen davon: Was um gottes willen macht das Repository im ViewModel

    d.h. jede Mini Abfrage die ich erledigen will soll über die BL laufen? Dann müsste ich ja defacto für alles eine eigene Businesslogik implementieren. Ganz ehrlich da gammeln ja noch viel mehr Functionen Subs und Klassen im Programm rum als notwendig wäre....
    Für mich war die Businesslogik mehr ein Sammelbecken für Aktionen mit der DB die ich öfter ausführe aber das ich alle Find und Get uns was auch immer darüber laufen zu lassen wäre mir jetzt nicht gekommen.

    Aber ok ich will es richtig machen somit für den nächsten Push:
    • Login Logik umbauen => Genereller Server User => Eventuell gesicherter Connectionstring (hab diesbezüglich gerade einen Artikel gelesen)
    • Businesslogik erweitern und verweis auf den DAL Layer aus dem VM nehmen
    mfG.
    Stephan
    Guten Morgen!

    kaifreeman schrieb:

    Aktuell ist ja im VM die Navigation Property hinterlegt, aber eigentlich mach es keinen Unterschied ob ich einen Collection mit den Benutzergruppen und eine separate Collection mit den dazugehörigen Rechten habe

    Wie du das in deinem VM machst bleibt natürlich dir überlassen, wie du dir leichter tust. Das VM soll die View "abbilden". Je nachdem wie du es machen willst.

    kaifreeman schrieb:

    wenn ich im Findby nach dem DeletedFlag frage trifft es ja nur die Benutzergruppen aber nicht die Berechtigungen.

    Ups, das habe ich übersehen. Fakt ist aber das hier Ef meiner Meinung für das zweite Where nicht mehr verwednet wird. Soll bedeuten das die Filterung auf nicht gelöschte dann im Ram passiert, kann mich aber irren, müsste ich probieren.
    Sowas sollte man mit einer Projektion machen (Select).

    kaifreeman schrieb:

    d.h. jede Mini Abfrage die ich erledigen will soll über die BL laufen? Dann müsste ich ja defacto für alles eine eigene Businesslogik implementieren. Ganz ehrlich da gammeln ja noch viel mehr Functionen Subs und Klassen im Programm rum als notwendig wäre....

    Verstehe jetzt nicht wo da der mehraufwand ist. Ob du die Methode im VM hast oder in der BL ist doch schnuppe.
    Klar, wenn man es einfach so im z.b. Konstruktor reinklatscht ja, aber im normalsfall bei einhaltung eines guten Stils hättest du für das Laden ja sowieso eine extra Methode ala GetAllUserRights(includeDeleted As Boolean) As List(Of Rights) in deinem VM. So hast du sie eben in der BL.

    kaifreeman schrieb:

    Für mich war die Businesslogik mehr ein Sammelbecken für Aktionen mit der DB die ich öfter ausführe

    Nene, alles was die Logik betrifft, und jegliches Daten abrufen, bearbeiten, hinzufügen ist ja Logik.

    Ein guter Tipp von mir (oder besser - ich erzähle wie ich es mache):
    Im VM schreibe ich einfach den code den ich benötige. Komme ich an einen Punkt an dem ich eine Abfrage (Daten) benötige oder etwas zurückschreiben möchte dann schreibe ich ganz einfach drauf los.
    Mir ist in dem Moment klar das es die Methode in der BL nicht gibt, erstmal egal. Also... ich schreibe: Dim allAviableRights As List(Of UserRight) = _myBl.GetAllAviableRights(currentUser.Id)
    So, nun wird mir "_myBl.GetAllAviableRights(currentUser.Id)" ROT markiert, da es die Methode nicht in der UserBL (oder wie auch immer die BL heißt) gibt.

    Nun STRG + . gedrückt und VS schlägt mir vor diese zu erstellen, und das sogar mit fast genau der Signatur die ich benötige. Also mach ich das und ich bin im Editor auch gleich an der Stelle und kann die Methode auch gleich mit Leben füllen. Ein hoch auf die moderne IDE. ^^

    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 hat mal wieder etwas länger gedauert aber ich war nicht untätig.
    1. Benutzerlogin umgebaut das ein genereller Benutzer verwendet wird (Die ganze Verschlüsselung habe ich zwar vorbereitet aber noch nicht final umgesetzt)
    2. Verweis von Viewmodel auf DAL Layer entfernt somit kein Repository mehr im Viewmodel
    3. Migration für die Datenbank implementiert und aktiviert
    Soweit so gut aber aktuell stellt es mich mal wieder komplett auf.

    im UsergroupAddEditVM wird ja durch den Navigationservice eine ID eines anzuzeigenden und zu bearbeitenden Objektes vom Typ Usergroup übergeben.

    Diese Funktion erledigt das für mich:

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Checks if the form is called for an add or edit if edit searches the correct usergroup and Sets it to the _EntityViewmodel
    3. ''' </summary>
    4. ''' <returns></returns>
    5. Public Overrides Function SetRealObject() As Boolean
    6. If ItemGuid = Guid.Empty Then
    7. 'Add mode:
    8. _EntityViewmodel = New UserGroupVM(New UserGroup)
    9. Else
    10. 'Edit mode:
    11. _EntityViewmodel = New UserGroupVM(BL.GetUserGroupById(ItemGuid,, True, True, True))
    12. End If
    13. RaisePropertyChanged("_EntityViewmodel")
    14. If DisplayMode = DisplayType.Edit Then _EntityViewmodel.BeginEdit()
    15. Return True
    16. End Function


    Soweit so gut, das klappt alles prima.
    Natürlich kann jeder Gruppe mehrere Berechtigungen mitgegeben werden.
    Hierzu gibt es eine Auswahlliste und ein Relaycommand das die ausgewählten Rechte empfängt und dem Object Usergroup (eigentlich ja dem UsergroupVM als Viewmodel) hinzufügen soll:

    VB.NET-Quellcode

    1. Private Async Sub AuthorizationsAdd(SelectedItems As Object)
    2. 'The SelectedItems is type of object because we receive a SelectedItemsCollection from the listview
    3. Dim vHelper As IList = CType(SelectedItems, IList)
    4. If vHelper Is Nothing OrElse vHelper.Count = 0 Then Return
    5. Dim vSelectedItemsList As IList(Of AuthorizationItem) = vHelper.Cast(Of AuthorizationItem).ToList
    6. Dim vStr As New StringBuilder("Sollen folgende Berechtigungen hinzugefügt werden?")
    7. vStr.AppendLine()
    8. For Each vItem As AuthorizationItem In vSelectedItemsList
    9. vStr.AppendLine(vItem.Name)
    10. Next
    11. Dim Result As MessageDialogResult = Await dialogCoordinator.ShowMessageAsync(Me, "Berechtigung hinzufügen", vStr.ToString, MessageDialogStyle.AffirmativeAndNegative)
    12. If Result = MessageDialogResult.Affirmative Then
    13. Dim vItemsToAdd As List(Of UserGroupRight)
    14. vItemsToAdd = BL.AddUserGroupRights(_EntityViewmodel.Id, vSelectedItemsList)
    15. If Not vItemsToAdd Is Nothing Then
    16. For Each vitem In vItemsToAdd
    17. _EntityViewmodel.NvUserGroupRights.Add(New UserGroupRightVM(vitem))
    18. Next
    19. End If
    20. End If
    21. End Sub


    In dieser Funktion benutze ich die beim Laden des Viewmodels erzeugte Businesslogik vItemsToAdd = BL.AddUserGroupRights(_EntityViewmodel.Id, vSelectedItemsList)
    Die Funktion in der Businesslogik ist wie folgt definiert:

    VB.NET-Quellcode

    1. Public Function AddUserGroupRights(_UserGroupId As Guid, _GroupRightsToAdd As IList(Of AuthorizationItem)) As List(Of UserGroupRight)
    2. Dim vInternalList As New List(Of UserGroupRight)
    3. If _UserGroupId = Guid.Empty OrElse _GroupRightsToAdd Is Nothing OrElse _GroupRightsToAdd.Count = 0 Then Return Nothing
    4. Dim query = _Repository.FindBy(Function(x) x.Id = _UserGroupId)
    5. query = query.Include("NvUserGroupRights")
    6. Dim vUserGroup As UserGroup = query.Single
    7. _Repository.Attach(vUserGroup)
    8. Dim vSavecounter As Integer = 0
    9. For Each vItem As AuthorizationItem In _GroupRightsToAdd
    10. 'In this particular case we can decide that if an Right has existing and the delete flag is set that we can remove the flag:
    11. Select Case vUserGroup.NvUserGroupRights.Where(Function(x) x.Authorization.ToLower = vItem.Key.ToLower).Count
    12. Case 0
    13. vSavecounter += 1
    14. Debug.Print("Savecounter: " & vSavecounter.ToString)
    15. Dim vNewItem As New UserGroupRight With {.Authorization = vItem.Key.ToLower, .GroupId = vUserGroup.Id}
    16. vInternalList.Add(vNewItem)
    17. vUserGroup.NvUserGroupRights.Add(vNewItem)
    18. vNewItem = Nothing
    19. Case 1
    20. 'check if deleted flag is set:
    21. Dim vFoundItem As UserGroupRight = vUserGroup.NvUserGroupRights.Where(Function(x) x.Authorization.ToLower = vItem.Key.ToLower).Single
    22. If vFoundItem.DeletedFlag Then
    23. vSavecounter += 1
    24. vFoundItem.DeletedFlag = False
    25. vFoundItem.DeletedTimestamp = Nothing
    26. vInternalList.Add(vFoundItem)
    27. End If
    28. Case Else
    29. Debug.Print("Mehrere Benutzerberechtigungen gefunden " & vItem.Key)
    30. End Select
    31. Next
    32. If Not _Repository.Save = vSavecounter Then Then Throw New Exception("Nicht alle Benutzerrechte wurden gespeichert")
    33. If vInternalList Is Nothing OrElse vInternalList.Count = 0 Then
    34. Return Nothing
    35. Else
    36. Return vInternalList
    37. End If
    38. End Function


    Das ganze funktioniert auch wieder ganz gut aber nur EINMAL, wenn ich das Fenster nicht schließe und das Command nochmals ausführe stellt es das Programm mit der Exception:
    Spoiler anzeigen

    System.InvalidOperationException: 'The instance of entity type 'UserGroup' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.'

    in der Zeile _Repository.Attach(vUserGroup) auf.

    Da ich nicht ganz blöd bin (was ich mir aber irgendwie seit der Layertrennung täglich vorkomme) denke ich mir, klar mein DBContext hat diese Entität ja schon in der Verwaltung also frage ich mal vor dem Attach ab ob das Ding bereits "attached" ist:

    VB.NET-Quellcode

    1. Public Overridable Function IsAttached(entity As T) As Boolean
    2. Debug.WriteLine($"Check if entity of Type {GetType(T).ToString} is attached")
    3. Return CType(_entities, MyERP2Context).Set(Of T)().Local.Any(Function(x) x IsNot entity)
    4. End Function


    Effekt Code läuft durch aber der Datenbank interessiert das Save Event damit mal wieder überhaupt nicht, was eigentlich auch wieder logisch ist weil ja das Objekt ein anderes ist und der DBContext ja nur nach der "ID" abfragt.

    Irgendwie bin ich somit mal wieder mit nem falschen Ansatz unterwegs.
    Viewmodel darf nix vom DAL wissen => OK akzeptiert
    Businesslogik darf keine Referenz zurück zum Viewmodel haben => OK akzeptiert

    Was ist in diesem Fall die richtige Vorgehensweise?
    Referenz der BL auf das VM erstellen und der BL einfach das Viewmodel übergeben und dort die Logik ausführen??
    oder soll ich im Repository ein GetAttachedElement einbauen??

    Im Endeffekt ist das Szenario total Simpel. Ich hab ja nur 2 Entitäten die mit 1:n verknüpft sind und will nur der n Seite etwas übergeben und einfach nur ein Update meiner View ;(
    mfG.
    Stephan

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

    Hallo @kaifreeman

    Also, ich habe das Projekt nun mal am neuesten Stand geöffnet und mir angesehen. Starten war nicht da nun der Pfad zur Serverlist.xml aus der Registry ausgelesen wird ohne das bei nicht existieren des Schlüssels ein Default-Wert erstellt wird. OK, per Hand angelegt. Geht auch nicht, da vermutlich Schema anders. Also die aus dem Projekt genommen und wieder editiert. OK, Startet und Login klappt.

    Dann wollte ich mal probieren eine Rolle anzulegen, aber ich kann kein Feld bearbeiten, auch nicht wenn ich auf "Bearbeiten" im Ribbon klicke. Gut, rein ins ViewModel und nachsehen.
    Ich muss sagen. Du verzettelst dich da, das ist alles viel zu kompliziert und ich kann mir vorstellen das das nicht mehr Übersichtlich für dich ist. Die ViewModelBase ist eine Eierlegende Wollmilchsau.
    Warum das. Warum in einer ViewModelBase ein InEdit Kann etwa jedes View Editiert werden? Ich denke nicht.

    Gewisse Dinge löst du ZU kompliziert und denkst vieleicht um die Ecke, ich weis das es Anfangs verwirrend ist deshalb auch meine Befürchtung das DIESES Projekt vieleicht etwas sehr groß ist für den Anfang, aber gut, versuchen kann mans.
    Am Anfang gings ja noch, da ging es um Grundlegende Dinge, aber du hast mittlerweile sooo viel daran rumgebastelt das du den Horizont vermutlich nicht mehr siehst. Was auch verständlich ist, am Anfang verläuft man sich nun mal gerne. Aber man muss immer daran denken, auch wenn man eine etwas kompliziertere Projektstruktur hat sollte man den Code selbst immer so simpel halten wie es geht (ohne die Guidelines zu verletzen).

    Da ich mit diesem MVVM Light Zeugs nix anfange und hier in deinem Projekt etwas viel "herumschwirrt" kann ich dir gerne mal ein Beispiel erstellen wwelches ALLES enthält.
    Ich habe mal dieses Adressbuch erstellt. Das könnte ich ja mal adaptieren und zu 100% MVVM tauglich machen, ein Generisches Repository und eine Businesslogik einfügen.
    Eine Businesslogik wäre jetzt für ein Simples Adressbuch nicht unbedingt notwendig, aber es geht ja ums prinzip.
    Die Datenhaltung baue ich um auf EF Core.
    Und.... damit alles Hand und Fuß hat noch UnitTests damit man sehen kann das man in diesem "Design" wirklich nahezu 100% des Codes mit Tests abdecken kann.

    So hättest du ein Kleines simples Projekt welches ALLES abdenkt was du hier machen willst. Listenmanipulation, Dialoge, usw.

    Was haltest du davon?

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

    Guten Morgen Sascha,

    Die geänderten Startbedingungen hätte ich besser dokumentieren sollen, sry hatte vergessen zu erwähnen das ich den gesamten Prozess des Login umgeschmissen habe. Auch die Serverlist wurde dadurch beeinflusst. :/

    Die Viewmodelbase werde ich noch auseinanderdröseln, aktuell kann sie definitiv zu viel für alle Viewmodels, liegt auch daran das ich mich beim finalen GUI Design noch nicht entschieden habe was aber auch wieder einen Einfluss auf die Viewmodel Struktur nimmt.

    Wenn du wirklich Lust und Zeit hast so ein Demoprogramm zu schreiben wäre das grenz genial. Ich stimme dir definitiv zu das viele meiner Ansätze zu kompliziert sind leider gibt es irgendwie keine Simple Literatur die den Layeraufbau simpel und einfach erklärt und praxistaugliche Beispiele liefert, zumindest wäre mir kein Buch in die Hände gekommen.
    mfG.
    Stephan

    kaifreeman schrieb:

    leider gibt es irgendwie keine Simple Literatur die den Layeraufbau simpel und einfach erklärt und praxistaugliche Beispiele liefert, zumindest wäre mir kein Buch in die Hände gekommen.

    Das ist allerdings richtig.

    Da muss man aber gar nicht so weit gehen, reicht ja schon ein vernünftiges MVVM Beispiel wo alles was man benötigt enthalten ist zu suchen.
    Möchte man MVVM lernen (und um das zu lernen muss man es mal ohne diesen Frameworks probiert haben) findet man zig Beispiele wo jedes anders mit dem Thema umgeht und welche zum Teil sogar das Pattern verletzen.
    Geschweige denn das dort auf das öffnen von Dialoge, FileBrowserDialogen oder ähnlichem angesprochen wird, davon ist mal gar nicht die rede.

    Gut, werde mal was vorbereiten.

    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 Stephan,

    keine Angst, ichhabe nicht vergessen. Um ehrlich zu sein bin ich auch schon dabei ein Beispiel zusammen zu schreiben.
    Da ich es aber "richtig" machen möchte dauert es etwas länger. Sorry

    Ich dachte mir - Das könnte man gleich in dern Sourcecode-Austausch oder in die Tipps&Tricks Rubrik posten weshalb ich das auch schön sauber machen möchte.
    Deshalb mache ich es TDD (Test-Driven-Development) und das dauert etwas länger.

    Ich finde aber das man so das auch vieleicht besser die Vorteile von solchen Pattern wie UnitOfWork oder MVVM besser erkennen kann wenn man sieht das plötzlich fast 100% des Codes Testbar ist.
    Auch versuche ich in diesem Beispiel so viele verschiedene Dinge zu implementieren. So möchte ich unbedigt auch Messages (wie es MVVM Light hat) verwenden. Braucht man fast nie, deshalb muss ich schau wo ich das am besten einbaue. Ich möchte EagerLoading von EF aufzeigen - automatische Protokollierung von Änderungen usw.

    Einfach eben ein Beispiel wo Praxisnahe alles enthalten ist was an Fragen auftauchen könnte. Sorry, falls lange dauert.

    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 Sascha

    mach dir keinen Stress, ich liege gerade in einem Wellnesshotel und habe Holger Schwichtenbergs Buch dabei. (Ok Freundin ist sauer aber proggen geht vor ^^)

    ich freue mich mich schon auf das Beispiel. Inzwischen habe ich noch am MyERP ein paar Änderungen vorgenommen.

    Durch die Lektüre von Holgers Buch und nachdenken über die aufgeführten Software Architekturen glaube ich langsam meinen Denkfehler zu erkennen. Ich glaube das der Hauptfehler in meiner Architektur darin begründet liegt das ich für die Entäten Viewmodel Klassen eingeführt habe. Diese sollten aber in einer eigenen Assembly liegen und Business Objekte sein. Per Definition würde dann sowohl das Viewmodel diese Objekte kennen als auch die Businesslogic. Damit wären meines Erachtens nach viele Workarounds nicht mehr notwendig.
    mfG.
    Stephan

    kaifreeman schrieb:

    ich liege gerade in einem Wellnesshotel und habe Holger Schwichtenbergs Buch dabei. (Ok Freundin ist sauer aber proggen geht vor ^^)

    Das Buch ist super. Ich habs auch mehrmals gelesen. Aber pass auf - der WifeAkzeptanceFactor hat seine Grenzen :D

    kaifreeman schrieb:

    Per Definition würde dann sowohl das Viewmodel diese Objekte kennen als auch die Businesslogic. Damit wären meines Erachtens nach viele Workarounds nicht mehr notwendig.

    Ist aber komplizierter und imho eigndlich gar nicht nötig. Ausserdem hätte man eine weitere Abhängigkeit.

    Ich handhabe das immer so (obs gut ist oder nicht weis ich nicht - für mich klappt es gut) das ich ein VM habe. Dieses VM zeigt bzw. macht das was die View dann auch darstellt.
    Was das ist ist erstmal nebensache. Je nachdem was ich für Daten dafür benötige (Entitäten) lasse ich mir diese von der Businesslogik reichen. fast immer ist dies in Form von Model-Objekten - also Entitäten.

    Die Properties in diesem VM geben dann einfach den Wert aus der Entität wieder bzw. setzen den Wert in der Enität direkt im Setter des Property. Der Vorteil am direkten schreiben in die Entitäts-Instanz ist das der ChangeTracker auch über mehrere Layer hinweg (Repository -> Businesslogi -> ViewModel) die Änderungen in der Entitätsinstanz mitbekommt und ich dann jederzeit mit SaveChanges() speichern kann und die Vorteile des ChangeTrackers dabei nutze um wirklich nur geänderte Werte zurückzuschreiben.

    Aber keine Angst. Wenn ich das Beispiel Online stelle erkläre ich alles und mache auch Klasendiagramme mit rein damit man das zusammenspiel erkennt.

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