myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Gemeinschaft » .NET-Komponenten und C#-Snippets » Kleine Datenverarbeitung DatasetOnly
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Kleine Datenverarbeitung DatasetOnly

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
ErfinderDesRades
myCSharp.de-Poweruser/ Experte

avatar-3151.jpg


Dabei seit: 31.01.2008
Beiträge: 5.286


ErfinderDesRades ist offline

Kleine Datenverarbeitung DatasetOnly

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Anbei der Anfang einer "Quiz-Anwendung"

Das Konzept ist entstanden aus dieser Diskussion:  Wie designe ich die Datenbank für ein Quiz mit drei verschiedenen Fragearten? und setzt sie quasi etwas fort.
Ihr könnt gerne - wenn ihr wollt - Antworten posten, Erweiterungen, Verbesserungen, Alternativen - am besten wäre natürlich mit angehängtem, lauffähigen Zips, auf der Vorlage basierend oder auch from Scratch.

Datenmodell
Bildle gugge: QuizFrage ist Zuordnungstabelle einer m:n - Relation, deren Datensätze jeweils eine Frage einem Quiz zuordnet.

Problem1: Polymorphie
Das komplizierte ist jetzt, dass es 3 verschiedene Arten von Fragen gibt:
  1. SpellFrage: verlangt eine buchstaben-getreue Antwort
  2. BildFrage: Ein Bild wird gezeigt, dazu eine Frage, ebenfalls buchstaben-getreu zu beantworten
  3. McFrage - Multiple Choice: Mehrere Antwortmöglichkeiten, von denen eine richtig ist
Es handelt sich also um ein Polymorphie-Problem, und OOP-mäßig würde man dazu neigen, etwas mit geerbten Basisklassen oder Interfaces zu versuchen.
Richtige Polymorphie wird aber vom Dataset nicht unterstützt, und würfe auch Präsentations-Probleme auf, die imo erst in Wpf eine wirkliche Antwort finden (DataTemplates).

Hier ists so gelöst, dass ein QuizFrage-(Zuordnungs-)Datensatz gleich 3 Verweise hat, auf jede Frage-Art einen.
Business-Logik muss nun sicherstellen, dass immer mindestens 2 der Verweise genullt sind - anders gesagt: Dass ein Zuordnungs-Datensatz nur eine Frage zuordnet, nicht 3 verschiedene auf einmal.
Diese "Umgehung der Polymorphie" erweist sich bei der Präsentation als überraschend praktisch: Dem User werden die verschiedenen Frage-Arten ja als Spalten präsentiert, und indem er in eine Spalte eingibt hat er bereits die Art der zugeordneten Frage bestimmt.
großes Grinsen

Problem2: Multiple Choice
Ein anderer Trick ist die wechselseitige Relation zwischn McFrage und McAntwort:
Nämlich eine McFrage hat logisch viele Antwort(-Optionen), ist also übergeordnet.
Aber gleichzeitig hat sie auch einen Verweis (also einen Fremdschlüssel, untergeordnet) auf die richtige Antwort.
Gui-Logik sorgt nun dafür, dass wenn die DGV-Checkbox-Zelle der IsTrue-Spalte angeklickt wird, dass dann die Parent-Frage ihren Verweis auf diese Antwort setzt.
IsTrue ist übrigens eine berechnete Spalte, darin gar kein Wert eingebbar ist, sondern sie berechnet sich selbst, mit folgender Expression (eingetragen im Dataset-Designer):
count(child.ID)=1
also wenn es genau eine ChildRow gibt, ist dieses die richtige Antwort.
Da die ChildRow einer McAntwortRow aber gleichzeitig immer auch die ParentRow (McFrageRow) ist, kann es zu einer Antwort auch nur maximal 1 ChildRow geben.
Und wenn es sie gibt ist damit IsTrue true, und diese Antwort also als die einzig richtige gekennzeichnet großes Grinsen
(ups - mir fällt grad auf: das ist ja gar kein Multiple-Choice, da ist ja nur Choice geschockt )

ErfinderDesRades hat dieses Bild (verkleinerte Version) angehängt:
DatenModell.png
Volle Bildgröße

Dieser Beitrag wurde 21 mal editiert, zum letzten Mal von ErfinderDesRades am 26.02.2016 10:33.

26.02.2016 02:35 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
ErfinderDesRades
myCSharp.de-Poweruser/ Experte

avatar-3151.jpg


Dabei seit: 31.01.2008
Beiträge: 5.286

Themenstarter Thema begonnen von ErfinderDesRades

ErfinderDesRades ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Noch Bildle der Quiz-Zuordnungs-Ansicht:
Man sieht den ersten Quiz, und der hat 5 Fragen, und jede Frage verweist auf nur einen Frage-Typ.
Unten in der Zufügezeile kann man weitere Fragen zufügen.
In der vorletzten Zeile bin ich grad im Begriff, eine andere Frage anderen Typs zuzuordnen. Wenn ich das bestätige, wird dann die McFrage derselben Zeile genullt.

ErfinderDesRades hat dieses Bild (verkleinerte Version) angehängt:
QuizApp.png
Volle Bildgröße

Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von ErfinderDesRades am 26.02.2016 02:44.

26.02.2016 02:42 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
ErfinderDesRades
myCSharp.de-Poweruser/ Experte

avatar-3151.jpg


Dabei seit: 31.01.2008
Beiträge: 5.286

Themenstarter Thema begonnen von ErfinderDesRades

ErfinderDesRades ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hier noch der Zip-Anhang, und Code:

C#-Code:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;

namespace QuizApp {
   public partial class frmQuizApp : Form {
      private FileInfo _DataFile = new FileInfo(@"..\..\Data.xml");
      public frmQuizApp() {
         InitializeComponent();
         btLoad.Click += btLoad_Click;
         btSave.Click += btSave_Click;
         LoadData();
      }

      void btLoad_Click(object sender, EventArgs e) { LoadData(); }

      void btSave_Click(object sender, EventArgs e) {
         if (!this.Validate()) return;
         quizDts.WriteXml(_DataFile.FullName);
         quizDts.AcceptChanges();  // Doku lesen! AcceptChanges() bei hinterlegter Datenbank **nicht** verwenden! Unbedingt vorher Doku lesen und **verstehen**
         System.Media.SystemSounds.Asterisk.Play();
      }

      void LoadData() {
         quizDts.QuizFrage.ColumnChanged -= QuizFrage_ColumnChanged; // Event vor Massen-Operationen deaktivieren
         var bss = components.Components.OfType<BindingSource>().ToArray();
         foreach (var bs in bss) bs.RaiseListChangedEvents = false;
         quizDts.Clear();
         quizDts.ReadXml(_DataFile.FullName);
         quizDts.AcceptChanges();  // Doku lesen! AcceptChanges() bei hinterlegter Datenbank **nicht** verwenden! Unbedingt vorher Doku lesen und **verstehen**
         foreach (var bs in bss) {
            bs.RaiseListChangedEvents = true;
            bs.ResetBindings(false);
         }
         quizDts.QuizFrage.ColumnChanged += QuizFrage_ColumnChanged;
      }

      void QuizFrage_ColumnChanged(object sender, DataColumnChangeEventArgs e) {
         if (e.ProposedValue == null) return;
         quizDts.QuizFrage.ColumnChanged -= QuizFrage_ColumnChanged; // Event deaktivieren, sonst Selbst-Auslösung
         var tb = quizDts.QuizFrage;
         foreach (var col in new DataColumn[] { tb.SpellFrageIDColumn, tb.MCFrageIDColumn, tb.BildFrageIDColumn }) {
            if (col != e.Column && !e.Row.IsNull(col)) e.Row[col] = Convert.DBNull;
         }
         quizDts.QuizFrage.ColumnChanged += QuizFrage_ColumnChanged;
      }

      protected override void OnClosing(CancelEventArgs e) {
         if (quizDts.HasChanges()) {
            switch (MessageBox.Show(this, "Save Changes?", "Save Changes?", MessageBoxButtons.YesNoCancel)) {
            case DialogResult.Yes: btSave.PerformClick();
               break;
            case DialogResult.No:
               break;
            case DialogResult.Cancel: e.Cancel = true;
               break;
            }
         }
         base.OnClosing(e);
      }
      protected override void OnClosed(EventArgs e) {
         tabControl1.Dispose();
         base.OnClosed(e);
      }

      private void mCAntwortDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e) {
         var grd = (DataGridView)sender;
         if (grd.Columns[e.ColumnIndex].DataPropertyName != "IsTrue") return;
         var rwAntw = (QuizDts.MCAntwortRow)((DataRowView)bsMcFrageMcAntwort.Current).Row;
         var rwFrage = rwAntw.MCFrageRow;
         rwFrage.MCAntwortRow = rwFrage.MCAntwortRow == rwAntw ? null : rwAntw;
      }
   }
}

Also es ist noch "Klumpen-Architektur" Augenzwinkern , das würde man beim Weiter-Entwickeln diversifizieren.
Es ist auch nicht absturz-sicher, kann noch keine Bilder anzeigen, und wie man das Quiz nun spielt, hab ich mir noch nichtmal was zu ausgedacht.
Also falls sich jemand für interessiert, oder gar Lust hat, auch bischen was dran zu basteln, würde ich auch noch bischen weiter machen ansonsten lass ich das auf diesem "Proor-of-concept"-Stand.

geproofte Konzepte wären
  • streng typisiertes, relationales Datenmodell
  • Abspeichern und Laden ohne Db - die Xml ist sogar einfach in den Sources anzugucken smile
  • databinding-getriebene Oberfläche
  • crud-komplett (lesen, schreiben, ändern löschen aller Datensätze)
  • Save-Changes-Abfrage beim Schließen
  • Lösung des Problems der verschiedenen Frage-Typen
  • Lösung des Problems der Multiple-Choice-Antworten


Dateianhang:
unknown QuizApp.zip (29 KB, 143 mal heruntergeladen)

Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von ErfinderDesRades am 26.02.2016 03:09.

26.02.2016 02:47 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 3 Jahre.
Der letzte Beitrag ist älter als 3 Jahre.
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 22.07.2019 22:43