ADO.NET, Frage zu verknüpften Tabellen [solved]



  • Pro Tabelle ein DataSet? Aber dann ist die Verknüpfung im DataSet doch wieder dahin?



  • Wiso Du kannst z.B ein SELECT auf nur eine Tabelle der DB machen. Vom Frontend aus betrachtet über die Datenleitung zum SQl-Server.
    Anhand dieses SELECT bildet das DataSet die Beziehung, als Kopie, selbstverständlich ab. Da wird dann nichts drin stehen ist noch mit der Tabelle verknüpft etc.



  • Aber mom ich werde es mal antesten ich kann Dir dann mal Bescheid geben wenn es funzt:

    Datenadapter und verknüpfte Tabellen
    Das Vorhandensein von separaten Tabellen im Dataset hat unter anderem zur Folge, dass ein Datenadapter in der Regel nicht auf SQL-Befehle oder gespeicherte Prozeduren verweist, die Tabellen verknüpfen. Stattdessen werden die Informationen aus verknüpften Tabellen von verschiedenen Adaptern separat in das Dataset eingelesen. Danach wird ein DataRelation-Objekt verwendet, um die Einschränkungen zwischen den Dataset-Tabellen (z. B. sich überlappende Aktualisierungen) zu verwalten und Ihnen die Navigation zwischen verknüpften Hauptdatensätzen und untergeordneten Datensätzen zu ermöglichen.
    *

    D.h. Ich vollziehe es mal an einem Beispiel mit dem DataRelation-Objekt nach
    kann etwas dauern, ich hoffe Du hast etwas Zeit?



  • Variante 2 OleDbAdapter als Klasssenmember des Formular, mit
    2 lokalen DataSet in einer INSERTION-Methode (btnInsert_Click)

    private void btnInsert_Click(object sender, System.EventArgs e)
    		{
    			DataRow drNewThemenGebiet;
    			DataRow drNewVokabel;
    
    			DataSet dsThemengebiet = new DataSet();
    			DataSet dsVokabeln     = new DataSet();
    
    			/* Zwischen der Tabelle "Themengebiete" zur der Tabelle "Vokabeln"
    			 * besteht bei mir über "Themengebiete.Themengebiet" eine 1:n Beziehung nach "Vokabeln.Themengebiet"
                 * "Themengebiet" ist PS in Tabelle "Themengebiete" und FS in Tabelle "Vokabeln"
    			 */
    
    			oleDbDataAdapter1.Fill(dsThemengebiet);
    			oleDbDataAdapter2.Fill(dsVokabeln);
    
    			try
    			{
    
    				drNewThemenGebiet                 = dsThemengebiet.Tables[0].NewRow();
    				drNewThemenGebiet["Themengebiet"] = txtThemengebiet.Text;
    
    				drNewVokabel                      = dsVokabeln.Tables[0].NewRow();
    				drNewVokabel["Fehler"]            = txtFehler.Text; 
    				drNewVokabel["Themengebiet"]      = txtThemengebiet.Text;
    				drNewVokabel["WortDeutsch"]       = txtWortDeutsch.Text;
    				drNewVokabel["WortEnglisch"]      = txtWortEnglisch.Text;
    
    				// So jetzt reorganisieren wir in der DB die Tabelle "Themengebiet" mit neuen Daten
    				try
    				{
    					dsThemengebiet.Tables[0].Rows.Add(drNewThemenGebiet);
    					oleDbDataAdapter1.Update(dsThemengebiet);
    				}
    				catch(System.Exception ex)
    				{
    					// Du bekommst wenn ich bei mir versuch ein Themegebite was schon existiert hier eine MessagBox
    					// weil es ist was existent Aber es wird über die DB-Verbindung auch nichts eingefügt
    					// Datenintegrität ist also safe
    					MessageBox.Show(this,ex.Message);
    
    					// Und deshalb könnte ich eine MessageBox an der Stelle auch weglassen und das ignorieren.
    				}
    
    				// So jetzt reorganisieren wir in der DB die Tabelle "Vokabeln" mit neuen Daten an der Stelle sage ich es gibt mehrere Übersetzunge für ein Wort entsprechend ist meine DB auch ausgelegt
    				try
    				{
    					dsVokabeln.Tables[0].Rows.Add(drNewVokabel);
    					oleDbDataAdapter2.Update(dsVokabeln);
    				}
    				catch(System.Exception ex)
    				{
    					MessageBox.Show(this,ex.Message);
    				}
    
    				/* Zum prüfen ob reduntandte Datensätze entstehen oder ob Sie
    				 * durch eine enstprechend konfigurierte DB abgefangen werden
    				 * 
    				 * Ergebniss: Bei entsprechend konfigurierter DB wird die DB auf Datenintegrität
    				 * Testobjekt bei mir ACCESS
    				 * 
    				 * Relationen bleiben gewahrt!!! So wie die DB eben aufgesetzt ist
    				 */
    
    				dsThemengebiet.Clear();
    				oleDbDataAdapter1.Fill(dsThemengebiet); 
    				dataGrid1.DataSource = dsThemengebiet.Tables[0];
    
    				dsVokabeln.Clear();
    				oleDbDataAdapter2.Fill(dsVokabeln); 
    				dataGrid2.DataSource = dsVokabeln.Tables[0];
    			}
    			catch(System.Exception ex)
    			{
    				MessageBox.Show(this, ex.Message);
    			}
    		}
    

    Läuft über je ein Adapter pro Tabelle zum Insert nehme ich dann innerhalb der Methode pro Tabelle ein "lokales" DataSet. Die sind dann nur temporär solange vorhanden wie eben Lebensdauer der aufgerufene Methode ist.

    So im Projekt habe ich für jede tabelle die Daten bekommt 1 extra Adapter.
    Diese sind immer "für eine Tabelle konfiguriert" und haben auch nur ein INSERT und SELECT-Command für jeweilige Tabelle.

    Meine 1 Tabelle enthält für meinen Vokabeltrainer alle Themengebiete über eine Spalte "Themengebiet" dort habe ich beim erstellen in ACCESS das CONSTRAINT
    "UNIQE" draufgedrückt.

    So Du hast ja nun Angst das die Relationen kaputt gehen? Ich habs getestet
    also bei mir wird alles wenn die DB entsprechend konfiguriert ist eingehalten!
    Wenn der User was falsches versucht wird es um die Integrität zu wahren nicht von der DB gemacht.

    Ich bekomme über die DB-Connectiviy lediglich eine Exception in mein Frontend rein. "User Du wolltest etwas machen was laut DB nicht erlaubt ist, ich habe Dein Vorhaben mal ignoriert" ums mal umgangsdeutsch im Volksmud zu erklären. Das kann ich ignorieren oder ich verunsicher den User durch ein Meldungsfenster....



  • Ich weiss das Beispiel ist nicht mit dem DataRelation-Objekt damit mich jetzt niemand drauf festnagelt. Aber es tut bei mir seine Arbeit so wie erwartet.

    Das DataRelation-Objekt dient auch lediglich um Relationen festzustellen! Beispielsweise
    wenn ich ein SELECT auf Tabellen mache werde ich wenn Tabellen über PS und FS verknüpft sind entsprechendes in dem Objekt wiederfinden.

    Aber bekanntlich kann ich auch DB's bauen mit CREATE und verzichte auf PS und FSsses sollte man nicht machen. Dabei kann ich die Integrität nurnoch durch sinnvolle DML-SQL-Statments sicherstellen. Es gibt bekanntlich keine Einschränkungen.



  • DeinDataSetMitDerRelationAus2Tabellen.Clear();
    			DeinAdapterMitDerRelationAus2Tabelle.Fill(DeinDataSetMitDerRelationAus2Tabellen);
    			MessageBox.Show(DeinDataSetMitDerRelationAus2Tabellen.Tables.Count.ToString());
    

    Ich verwende ja ACCESS habe eine OledbAdapter der auf 2 verknüpfte Tabellen, ausgestattet mit FS und PS 1:n verbunden sind, konfiguriert ist!
    Trotzdem sagt mir mein DataSet es hat nur 1 Tabelle nach dem Fill

    An der Stelle kann ich Dein Problem bei mir schon nichtmehr nachsimulieren!
    Aber das Codebeispiel wie man ein INSERT auf solche Tabellen macht funktioniert
    bei mir. Es macht keine Redundanzen in die DB alle relationen bleiben gewahrt.

    Müsstes den Code nur auf deine struct ummünzen, dort wo ich über die TextBoxen zuweise muss Du deine Daten aus Deiner struct rausholen und
    in entsprechende Items der neuen Datenzeile quetschen! Und Du brauchst noch entsprechend deiner Aufgabe Dklaratione zu DataTable/DataRow-Objekten sollte klar sein...

    Gruss sclearscreen



  • Da hat man Dich wohl verdonnert ein Kundenauftragsystem vom SQL-Server
    in ein Frontend zu implementieren?

    Oder baust Dir wohl eine Erleichterung? Weil Du selbst aussendienstlich
    Auftragsaquise machst, um spät am Feierabend noch Neuaufträge auf den SQL-Server zu spielen!

    So ich geh erstmal und tütele an meinem Kram rum.



  • danke, werde ich morgen mal probieren, heute hatte ich keine Zeit. Ist im Übrigen ein Teil aus einem CRM System (soll es jedenfalls mal werden).

    Vielen Dank und schönen Gruß!



  • Okay, das Problem ist wohl, dass ADO.NET hinsichtlich Auto Werten bei mehr als einer Tabelle gern ins schwimmen kommt. Nach allem was ich ausprobiert habe, gibt es im Prinzip zwei Workarounds für dieses Problem.

    1. Im DataSet den betreffenden Tabellen mitteilen, dass die als ID einen Negativen Wert nehmen, und diesen abwärts inkrementieren sollen.
    So erzeuge ich einen neuen Mastertabellen Eintrag (ID -1) und muss diesen dann per

    TableAdapter.Update(Tablename);
    

    in den SQL Server schreiben.
    Nun ein SELECT Statement absetzen um den vom SQL Server an dieser Stelle wirklich zugewiesenen Key zu erfragen. Diesen dann in die Fremdschlüsselspalte der untergeordneten Tabelle einfügen. Die untergeordnete Tabelle, sofern sie denn den richtigen ID aus dem SQL Server bekommen hat, kann auch am Ende der for Schleife erst in den Server geschrieben werden.

    Der Vorteil hierbei ist, dass auch wenn mehrere User in der DB arbeiten, sie sich so nicht in die Quere kommen.

    2. Statt einer INT für den Primärschlüssel einfach einen GUID einsetzen, diesen, beim Einlesen des Datensatzes in die DataTable erzeugen und der untergeordneten Tabelle zuweisen. Zum Schluss die Tabellen in den Server schreiben. Funktioniert auch

    Hat beides Vor- und NAchteile und sollte beides auch in Umgebungen mit mehrerern Benutzern funktionieren.



  • Auch wenn Du es gelöst hast nur falls es von Interesse ist folgender Link
    sollte auch zur Thematik passen.

    MSDN über automatische Primärschlüssel

    Dieses PDF habe ich jetzt auch schon mal meinem Datenmoloch gegeben.


Anmelden zum Antworten