Laden...

Mergen von Rows in einer DataTable

Erstellt von TheLion092 vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.120 Views
T
TheLion092 Themenstarter:in
17 Beiträge seit 2018
vor 4 Jahren
Mergen von Rows in einer DataTable

Hallo 🙂

Kurz vorweg, ich bin Anfänger auf dem Gebiet der C#/WPF Programmierung, also bitte nich zu sehr haten =) Ich bin Systemadministrator und kein gelernter Programmierer.

Für mein Unternehmen bin ich derzeit dabei ein kleines Programm zu schreiben, was alle User die auf einen bestimmten Ordner auf einem Netzlaufwerk NTFS Rechte haben, auflistet. Sprich ich möchte sehen, wer z.B. auf G:\Verwaltung\Aufträge Lese- und Schreibrechte hat, und dies dann in einer Tabelle aufgelistet haben. Die erste Erleichterung: Mein Programm ist so gut wie fertig. Ich lasse mir alle AD-Gruppen für einen Ordner auslesen und lese dann aus diesen AD-Gruppen wiederum alle User aus. Die Benutzer werden in einer DataTable gespeichert und dann im Programm an ein DataGrid weitergegeben. Bedingt durch unsere ActiveDirectory-Architektur kommt es vor, dass User auf einen Ordner mehrmals über verschiedene Gruppen Lese-Schreibberechtigung bekommen. Bedeutet also, in meiner Tabelle habe ich Duplikate. Nun möchte ich diese doppelten Zeilen löschen, so dass nur noch eine da ist. Der Knackpunkt ist aber, dass für Duplikate in Spalte 1 unterschiedliche Werte in Spalte 4 und 5 stehen können. Die Spalte 1 mit der Mitarbeiter-Nummer ist hierbei eindeutig. Wie filtere ich jetzt die DataTable, dass sie mir das gewünschte Ergebnis anzeigt ?

Beispiel:
User für G:\Verwaltung\Aufträge

Mitarbeiter-Nummmer | Vorname| Nachname | Rechte | AD-Gruppe

155484 |Max | Mustermann | Lesen | verwaltung-read
154574 |Klaus | Müller | Lesen | verwaltung-read
154574 |Klaus | Müller | Schreiben | administratoren

Was ich haben möchte:

Mitarbeiter-Nummmer | Vorname| Nachname | Rechte | AD-Gruppe

155484 |Max | Mustermann | Lesen | verwaltung-read
154574 |Klaus | Müller | Lesen, Schreiben | verwaltung-read, administratoren

Ich habe hier aktuell eine Funktion, welche mir zuverlässig Duplikate entfernt, jedoch werden dadurch keine Zellen aus Spalte 4 und 5 gemerged


public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
        {
            Hashtable hTable = new Hashtable();
            ArrayList duplicateList = new ArrayList();

            //Add list of all the unique item value to hashtable, which stores combination of key, value pair.
            //And add duplicate item value in arraylist.
            foreach (DataRow drow in dTable.Rows)
            {
                if (hTable.Contains(drow[colName]))
                {
                    duplicateList.Add(drow);
                }
                else
                {
                    hTable.Add(drow[colName], string.Empty);
                }
            }
            //Removing a list of duplicate items from datatable.
            foreach (DataRow dRow in duplicateList)
            {
                dTable.Rows.Remove(dRow);
            }
            //Datatable which contains unique records will be return as output.
            return dTable;
}

Vielleicht kann mir ja jemand helfen 😁
Liebe Grüße

16.832 Beiträge seit 2008
vor 4 Jahren

WPF ist so konzipiert, dass Daten gebunden werden ([Artikel] MVVM und DataBinding).
Agierst Du direkt in der UI ohne Bindung, wirst Du in WPF von Fallstrick zu Fallstrick stolpern.
WinForms war da gutmütiger, auch wenn dort auch schon Binding das richtige Mittel der Wahl war.

Besser wäre es, wenn Du die Nutzer in einer Liste führen würdest und diese Liste bearbeiten würdest.
Die Liste kannst Du dann an die UI Binden und wird jederzeit aktualisiert (automatisch), sobald sich die Liste (oder deren Inhalte) ändert.
Sie selbst ist natürlich dann mit allen Mitteln manipulierbar (Filter, Sortierung...).
Dazu musst Du aber MVVM anwenden.

Kleine Hinweise:

  • Es ist eine Methode, keine Funktion
  • ArrayListen sollten nicht ververwendet werden (sonder List<T> und Konsorten)
  • Die DataTable hat auch ausgedient (in MVVM eben mit Listen und Objekten).
W
955 Beiträge seit 2010
vor 4 Jahren

Wenn du -wie Abt schreibt- Modellobjekte verwendest bist du flexibler da sie beispielsweise Methoden enthalten können und somit Verhalten kapseln können.
Bei deinem Problem könnte man LINQ verwenden also funktionale Programmierung. Mit Modellobjekten könnte das so aussehen (DataTables unterstützen auch LINQ muss man fairerweise zugeben):


        public class GrantedAccess
        {

            public string Id           { get; set; }
            public string Surname      { get; set; }
            public string Name         { get; set; }
            public string Accesstype   { get; set; }
            public string Group        { get; set; }
        }


        static void Main(string[] args)
        {

            var list = new List<GrantedAccess> { 
                
                new GrantedAccess { Id = "155484", Surname = "Max", Name = "Mustermann", Accesstype="Lesen", Group="verwaltung-read" },
                new GrantedAccess { Id = "154574", Surname = "Klaus", Name = "Müller", Accesstype="Lesen", Group="verwaltung-read" },
                new GrantedAccess { Id = "154574", Surname = "Klaus", Name = "Müller", Accesstype="Schreiben", Group="administratoren" }
            };


            var result = list.GroupBy(p => p.Id)
                             .Select(p => new GrantedAccess { Id = p.Key,
                                                              Surname = p.Select(q => q.Surname).First(),
                                                              Name = p.Select(q => q.Name).First(),
                                                              Accesstype = string.Join(", ", p.Select(q => q.Accesstype).Distinct().ToArray()),
                                                              Group = string.Join(", ", p.Select(q => q.Group).Distinct().ToArray()) })
                             .ToList();


            result.ForEach(p => Console.WriteLine($"{p.Id}|{p.Surname}|{p.Name}|{p.Accesstype}|{p.Group}"));
            Console.ReadLine();
        }

T
TheLion092 Themenstarter:in
17 Beiträge seit 2018
vor 4 Jahren

Hmm... wahrscheinlich verstehe ich es nur falsch, aber ich war eigentlich der Meinung, ich hätte das mit dem DataBinding gemacht. Sobald ich was in der DataTable ändere, ändern sich auch die Daten im DataGrid.


public DataTable dt { get; private set; } = new DataTable();

private void Datagrid_Loaded(object sender, RoutedEventArgs e)
{
	dt.Clear();
	dt.Columns.Add("IDM-Nummer", typeof(string));
	dt.Columns.Add("Vorname", typeof(string));
	dt.Columns.Add("Nachname", typeof(string));
	dt.Columns.Add("Berechtigung", typeof(string));
	dt.Columns.Add("Gruppe", typeof(string));
	Datagrid.ItemsSource = dt.DefaultView;
}


<DataGrid Grid.Row="1" x:Name="Datagrid" GridLinesVisibility="None" HeadersVisibility="Column" SelectionMode="Single" IsReadOnly="True" ItemsSource="{Binding}" Loaded="Datagrid_Loaded"/>

Den Aspekt, dass man keine DataTable mehr verwenden soll, sondern lieber eine List, werde ich mir nochmal anschauen.

T
461 Beiträge seit 2013
vor 4 Jahren

.) Ich lasse mir alle AD-Gruppen für einen Ordner auslesen und lese dann aus diesen AD-Gruppen wiederum alle User aus.
.) Die Benutzer werden in einer DataTable gespeichert und dann im Programm an ein DataGrid weitergegeben.

Hallo,

wie schon von den Vorrednern gepredigt, sollte man hier eher Klassen-Objekte erstellen, die so einen gewünschten Datensatz wie du ihm haben willst, aufgebaut ist.
Und anstatt jetzt den 2ten Punkt dazu zu verwenden, die Daten in eine DataTable zu schreiben, befüllst du einfach jeden Benutzer in ein so eine Klasse und hast als Ergebnis eine Liste mit Benutzern die jeweils in Klassen sitzen 😁

Unter Umständen kannst du schon beim Befüllen der Klassen mit einer eindeutigen Id in jedem Schleifendurchlauf nach einer vorhandenen Klasse mit derselben Id in der Liste suchen. Wenn gefunden ergänzt du einfach die Daten, ansonsten erstellst einfach wieder eine neue Klasse.

Somit bekömmst du dann schon die fertig anwendbare Klassenliste aller Benutzer.

Diese Liste kann man dann genauso an das DataGrid oder andere Controls binden...

Grüße

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

16.832 Beiträge seit 2008
vor 4 Jahren

Kleinigkeiten:

  
        public class GrantedAccess  
        {  
  
            public string Id           { get; set; }  
            public string Surname      { get; set; }  
            public string Name         { get; set; }  
            public string Accesstype   { get; set; }  
            public string Group        { get; set; }  
        }  
  

So würde ich das Modell auch gestalten, mit der Ausnahme:

  • Id suggeriert einen echten Identifier basierend auf Guid oder int - und wir haben hier wohl int
  • AccessType sollte ein Enum sein
  • GroupName würde besser passen (Group suggeriert in OOP ein Objekt)
T
TheLion092 Themenstarter:in
17 Beiträge seit 2018
vor 4 Jahren

Ich werde mal etwas rumprobieren und mich dazu belesen.

Vielen Dank erstmal an alle 😃
Liebe Grüße