Laden...

Wie können Relationen sortiert werden?

Erstellt von perlfred vor 8 Monaten Letzter Beitrag vor 8 Monaten 467 Views
P
perlfred Themenstarter:in
261 Beiträge seit 2010
vor 8 Monaten
Wie können Relationen sortiert werden?

Hallo!

Wie sortiert man denn das Feld einer Relation?

Ich habe eine (Basis) Liste die ein Feld (Regisseur) enthält, dass eine ID auf einen Listen-Eintrag in einer anderen Liste (Regisseur-Liste), enthält.

Jetzt möchte ich die Basis-Liste nach den Regisseur-Feld sortieren. Natürlich möchte ich nicht die Regisseur-IDs sortieren, sondern die den ID's entsprechenden Regisseur-Einträge nach den Regisseur-Namen.

cvsDVDEinträge.SortDescriptions.Clear();                             // Alle/Alte Sortierung (immer) löschen

SortDescription sdRegisseur = new("Regisseur-ID", FeldSortierung);		// Sortierung nach Regisseur

cvsDVDEinträge.SortDescriptions.Add(sdRegisseur);                  // Sortierung auf die CollectionViewSource übertragen          

Wie gebe ich denn eine Funktion (die in meinem Beispiel aus der Regisseur-ID den Regisseur-Namen ermittelt) in der SortDescription an?

SortDescription sdRegisseur = new( GetRegisseurName(Regisseur-ID, Regisseur-Liste), FeldSortierung);		// Sortierung nach Regisseur
T
2.226 Beiträge seit 2008
vor 8 Monaten

Im einfachsten Fall in dem du einfach die richtige Porperty angibt.
Wenn du keine dafür hast, dann leg doch eine an.
Warum brauchst du überhaupt eine extra Methode dafür?
Klingt nämlich nach einem fehlerhaften Datenmodell.

T-virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

P
perlfred Themenstarter:in
261 Beiträge seit 2010
vor 8 Monaten

Hallo T-Virus!

Danke für deine Überlegung(en)!

Mit dem fehlerhaften Datenmodell könntest du vielleicht recht haben, aber ganz so einfach ist es dann doch nicht ...

Mal zur Ausgangssituation:

Ich verwende in dieser Applikation keine relationale Datenbank sondern deserialisiere (mehere) XML-Dateien in Listen (unterschiedlichem Daten-Typs).

Als Beispiel eine Liste vom Datentyp DVDEintrag List<DVDEintrag> und eine Liste vom Datentyp Regisseur List<Regisseur>.

Der Datentype DVDEintrag hat (50 andere Eigenschaften) und eine Eigenschaft Regisseur (vom Type long).

Der Datentype Regisseur hat (10 andere Eigenschaften) und eine Eigenschaft ID (vom Type long).

In der Eigenschaft Regisseur vom DVDEintrag wird der Wert der ID-Eigenschaft eines Regisseur-Eintrages gespeichert.

Ganz klassische N:1 Relation.

Die DVD-Liste dient als Source einer ICollectionView, die ich in der View der Applikation, als Source an eine ListView binde.

/// <summary>
/// Liste der DVD-Einträge.
/// </summary>
private List<DVDEintrag> DVDEinträge { get; set; }

internal CollectionViewSource CVSDVDEinträge { get; set; } = new CollectionViewSource();    // CVS deklarieren

/// <summary>
/// View der DVD-Einträge Liste.
/// </summary>
public ICollectionView DVDEinträgeView { get => CVSDVDEinträge.View; }

...

CVSDVDEinträge.Source = DVDEinträge;    // (Neue) Liste der DVD-Einträge der CVS zuordnen
DVDEinträgeView.Refresh();              // Daten-View aktualisieren

Die ICollectionView benutze ich zum Filtern und Sortieren der DVD-Einträge. Und genau an dieser Stelle kann ich beim Sortieren die Relation (zu den Regisseur-Einträgen) nicht abbilden.

Jetzt zu deinen Überlegungen:

  • Die richtige Property → Habe ich eigentlich. Regisseur-Eigenschaft der DVD-Liste.
  • Leg doch eine (Neue) an → Was soll da drin stehen? Der Name des Regisseurs? Dann hätte ich Datenredundanz und müsste die Aktualisierung steuern
  • Warum brauchst du eine Methode? → Diese soll die Relation abbilden und den Namen des Regisseurs für die Sortierung "holen"

Den einzigen Ausweg den ich zur Zeit sehe ist, der Source für die ICollectionView eine View zu übergeben (in der die Regisseur-Name Relation bereits aufgelöst ist).

object MyDVDEintragView = from myDVDListe in DVDListe
                          join myRegisseurListe in MyRegisseurListe on myDVDListe.Regisseur equals myRegisseurListe.ID
                          select new { myDVDListe.*, myRegisseurListe.Name };

CVSDVDEinträge.Source = MyDVDEintragView ;    // (Neue) Liste der DVD-Einträge der CVS zuordnen

Ich habe aber das Gefühl, dass das nicht der richtige Weg ist. Ich habe ja noch viele Relationen ...

Und ich habe auch keinen richtigen Daten-Type mehr, die View ist ja vom Type: object!

T
2.226 Beiträge seit 2008
vor 8 Monaten

Und was spricht dagegen, dir ein eignes Modell für die View anzulegen anstelle mit deinen Entitäten zuarbeiten?
Dann hättest du auch gleich die Eigenschaft mit dem Namen und kannst danach sortieren.
Aktuell müsstest du ja zwangsweise genau den Weg mit einer vorsortierten Datenquelle gehen, wenn du kein passendes Datenmodell für die Anzeige verwendest.

Anbei verwendest du hier XML Dateien auch als Ersatz für eine Relationale Datenbank.
Hier könntest du auch leicht auf Sqlite als lokale Datebnbank umsteigen, aber das ist ein anderes Thema.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

P
perlfred Themenstarter:in
261 Beiträge seit 2010
vor 8 Monaten

Hallo T-Virus!

Irgendwie reden wir aneinander vorbei.

Ich habe doch ein Model für die View. Meine Eigenschaft die ich in der View binde ist die DVDEinträgeView eine ICollectionView Darüber steure ich die Sortierung!  Mir ist noch ein bisschen unklar, wie du mit der separaten Eigenschaft eine Sortierung erzeugen willst?

Die ICollectionView hat als Source eine Liste (Enumerable) und diese Liste muss ein Feld enthalten, nach dem sortiert werden kann. Ich habe als Ausgangspunkt immer zwei Listen die über eine Relation verbunden sind. Also muss ich als erstes eine View erzeugen, die  mir das RelationsFeld (in der gewünschten Form aufbereitet) zur Verfügung stellt.

Ich habe das jetzt so gelöst, dass ich 1.  einen separaten Datentype erstelle, der mir den ursprünglichen Datentype durch die Relations-Feld(er) erweitert:

/// <summary>
/// Hilfs-Klasse zur Strukturierung von DVD-Einträgen für die Sortierung.
/// </summary>
public class DVDEintragSort
{
    /// <summary>
    /// DVD-Eintrag.
    /// </summary>
    public DVDEintrag DVDEintrag { get; set; }

    /// <summary>
    /// Der Name des Regisseurs des DVD-Eintrages (aufbereitet für eine Sortierung).
    /// </summary>
    public string RegisseurBezeichnung { get; set; }

    public DVDEintragSort(DVDEintrag dVDEintrag, string regisseurBezeichnung = "")
    {
        DVDEintrag = dVDEintrag; RegisseurBezeichnung = regisseurBezeichnung;
    }
}

2. Eine Eigenschaft die ich als Quelle für die ICollectionView benutze deklariere:

/// <summary>
/// Liste der DVD-Einträge mit aufgelösten Relationen
/// </summary>
private List<DVDEintragSort> DVDEinträgeSort { get; set; }

und 3. in diese die ursprünglichen Daten (DVD-Liste) und die Daten der aufgelösten Relationen übernehme:

DVDEinträgeSort = 
(from DVD in DVDEinträge
                   join Reg in RegisseurListe on DVD.Regisseur equals Reg.ID
                   select new DVDEintragSort( DVD, new string((Reg.Nachname + ", " + Reg.Vorname).Trim()))).ToList(); // DVD-Eintrag + Relation(en) 

und diese als Quelle der ICollectionView zur Verfügung stelle:

CVSDVDEinträge.Source = DVDEinträgeSort;    // (Neue) Liste der DVD-Einträge der CVS zuordnen
DVDEinträgeView.Refresh();                  // Daten-View aktualisieren

Jetzt kann ich in der Sortierung, sowohl Eigenschaften die in der originalen DVD-Liste als auch Eigenschaften die durch die Relation erstellt worden sind, ansprechen/benutzen.

    string FeldName;                                                                                  // Feld-Name deklarieren
    switch (SortierungsFeldDVDÜbersicht)
    {
        case EnuSortierungsFelderDVDÜbersicht.Rating:  FeldName = "DVDEintrag.ERating"; break;
        case EnuSortierungsFelderDVDÜbersicht.Genre: FeldName = "DVDEintrag.Genre"; break;
        case EnuSortierungsFelderDVDÜbersicht.Land: FeldName = "DVDEintrag.Land"; break;
        case EnuSortierungsFelderDVDÜbersicht.Jahr: FeldName = "DVDEintrag.Jahr"; break;
        case EnuSortierungsFelderDVDÜbersicht.Dauer: FeldName = "DVDEintrag.Dauer"; break;
        case EnuSortierungsFelderDVDÜbersicht.Regisseur: FeldName = "RegisseurBezeichnung"; break;
        default: FeldName = "DVDEintrag.Titel"; break;
    }

    ListSortDirection FeldSortierung = SortierungsRichtungDVDÜbersicht == EnuSortierungRichtung.Aufsteigend // Sortierung aus Aufzählungs-Wert ableiten
                                        ? ListSortDirection.Ascending : ListSortDirection.Descending;
    SortDescription sdDatenView = new(FeldName, FeldSortierung);                                            // Sortierung (aus den Sortier-Eintrag Werten) erstellen
            
    CVSDVDEinträge.SortDescriptions.Add(sdDatenView);                                                       // Sortierung auf die CollectionViewSource übertragen (Die Sortierung selbst wird erst mit der Refresh-Methoder der DatenView ausgeführt!)                

Durch die Hilfsklasse ist dann auch eine eindeutige Zuordnung in XAML wieder gegeben:

<ListView.View>
    <GridView>
        <!-- DVD-Nr.  = über den DVD-Eintrag -->
        <GridViewColumn Header="DVD-Nr." >
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding DVDEintrag.Nummer}" Foreground="Blue"
/>
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
    ...
        <!-- Regisseur  = über die Relation -->
        <GridViewColumn>
            <GridViewColumn.CellTemplate>
                 <DataTemplate>
                    <TextBlock Text="{Binding RegisseurBezeichnung}" 
/>
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
T
2.226 Beiträge seit 2008
vor 8 Monaten

Und genau das meinte ich damit, dass du dir ein passendes Datenmodell anlegen solltest.
Dann kannst das ganze auch erst sinnvoll und mit den vorgesehen Techniken umsetzen.
Hättest du doch gleich drauf kommen können oder?

Nachtrag:
Das entspricht dann auch dem Konzept der Projektion wenn man gegen Relationalen Datenbanken arbeitet.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

P
perlfred Themenstarter:in
261 Beiträge seit 2010
vor 8 Monaten

Hallo T-Virus!

Ich sage jetzt mal Ahaaa! 😃 Die Hilfs-Klasse hätte ich nicht mit DataModel gleichgesetzt.

Trotzdem vielen Dank!