Announcement

Collapse
No announcement yet.

dringendes (und merkwürdiges) Problem mit DataSet, DataBindings und Update

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • dringendes (und merkwürdiges) Problem mit DataSet, DataBindings und Update

    Hallo zusammen!

    Ich habe ein etwas merkwürdiges Problem, an dem ich völlig verzweifele (u.a. weil ich sehr viel Zeitdruck hab, und schon sehr viel Zeit in dieses Problem investiert habe)
    Ich bin für jegliche Hilfe EXTREM dankbar!!

    Ich benutze einen ODBCDataAdapter (mit selbstgebastelen Select, Update ect Commands), ein untypisiertes DataSet und eine Access DB.
    In meinem Fenster ist eine Listbox, die mir per Binding Firmennamen anzeigt.Darunter sind Textboxen für die Firmendetails
    Wähle ich einen aus, werden unten die Details der Firma angezeigt. Das ganze funzt einwandfrei per DataBinding.
    Nun gehts aber los:
    Ich wähle eine Firma aus. Ich ändere ihren Namen.
    Wenn ich nun firmsDataSet.HasChanges() abfrage, sagt er mir keine Änderung. Obwohl die Änderung im DataSet ist (das sehe ich wenn sie mir in eine XML Datei schreiben lasse).
    Die einzige Möglichkeit, die mein DataSet davon überzeugt, die RowState Property richtig zu setzen, ist wenn ich in der Listbox NACH der Ändernung den SelectedIndex auf -1 (also keines) setze. DANN ergibt HasChanges true, und per Binding wird auch der neue Name in der Listbox angezeigt
    Aber als wenn nun alles gehen würde...
    Rufe ich nun die Update-Methode des DataAdapters auf, bekomme ich den ERROR [HY090] - Ungültige Zeichen oder Pufferlänge.
    Aber an dem UpdateCommand des Adapters kann es aber eigentlich nicht liegen, denn wenn ich einfach updateCom.ExecuteNonQuery(); aufrufe, updated er die Datenbank (mit falschen Daten, aber das liegt wohl an meiner Parameterzuweisung), ABER der Name in der Listbox wird NICHT geändert (im Textfeld Name darunter aber wird wiederum der richtige angezeigt).

    So hier der Code:

    Zuerst die DataBindings:
    .
    this.lstBx_Firmen.DataSource = Ergo.MainApp._FirmDB._FirmsDataSet;
    this.lstBx_Firmen.DisplayMember = "Firmen.Name";
    .

    this.txtBx_Name.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Name");
    .
    this.txtBx_Zusatz.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Zusatz");
    .
    this.txtBx_Straße.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Straße");
    .
    this.txtBx_Ort.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Ort");
    .
    this.txtBx_PLZ.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.PLZ");
    .
    this.txtBx_Postfach.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Postfach");
    .
    this.txtBx_Tel.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Tel_Nr");
    .
    this.txtBx_Fax.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Fax_Nr");
    .
    this.txtBx_Mobil.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.Mobil_Nr");
    .
    this.txtBx_Mail.DataBindings.Add("Text", Ergo.MainApp._FirmDB._FirmsDataSet, "Firmen.E_Mail");
    .
    ohne diese Zeile weigert sich das DataSet, jegliche Änderung anzuerkennen:
    .
    this.lstBx_Firmen.SelectedIndex = -1;
    .

    hier der Init des Adapters und des DataSets (Insert/Delete Teil weggelassen):
    .
    private void BuildUpDataSet()
    {
    firmsDataAdapter = new OdbcDataAdapter();
    firmsDataSet = new DataSet("FirmenDataSet");
    .

    // ==============
    // SELECT command
    // ==============
    string selectStr = "SELECT * FROM Firmen";
    OdbcCommand selectCom = new OdbcCommand(selectStr, Ergo.MainApp._ErgoDB._MyConnection);

    // ==============
    // UPDATE command
    // ==============
    string updateStr = "UPDATE Firmen SET " +
    "Name = ?, Zusatz = ?, Ort = ?, PLZ = ?, " +
    "Postfach = ?, Straße = ?, Tel_Nr = ?, " +
    "Fax_Nr =?, Mobil_Nr = ?, E_Mail = ? " +
    "WHERE ID_Firma = ? ";
    updateCom = new OdbcCommand(updateStr, Ergo.MainApp._ErgoDB._MyConnection);
    .
    // add the parameters to the collection
    updateCom.Parameters.Add("Name", OdbcType.Text, 50, "Firmen.Name");
    updateCom.Parameters.Add("Zusatz", OdbcType.Text, 100, "Firmen.Zusatz");
    updateCom.Parameters.Add("Ort", OdbcType.Text, 50, "Firmen.Ort");
    updateCom.Parameters.Add("PLZ", OdbcType.Text, 50, "Firmen.PLZ");
    updateCom.Parameters.Add("Postfach", OdbcType.Text,50, "Firmen.Postfach");
    updateCom.Parameters.Add("Straße", OdbcType.Text, 100, "Firmen.Straße");
    updateCom.Parameters.Add("Tel_Nr", OdbcType.Text, 50, "Firmen.Tel_Nr");
    updateCom.Parameters.Add("Fax_Nr", OdbcType.Text, 50, "Firmen.Fax_Nr");
    updateCom.Parameters.Add("Mobil_Nr", OdbcType.Text,50, "Firmen.Mobil_Nr");
    updateCom.Parameters.Add("E_Mail", OdbcType.Text, 50, "Firmen.E_Mail");
    .
    // add the primary key parameter
    OdbcParameter pU = new OdbcParameter("ID_Firma", OdbcType.Int, 50, "Firmen.ID_Firma");
    pU.SourceVersion = DataRowVersion.Original;
    updateCom.Parameters.Add(pU);

    // fill the dataSet
    try
    {
    firmsDataAdapter.Fill(firmsDataSet, "Firmen");
    }
    catch(OdbcException ex)
    {
    MessageBox.Show(ex.Message, "Fehler beim Füllen des DataSets");
    }

    // set primary key column
    DataColumn [] keys = new DataColumn[1];
    keys[0] = firmsDataSet.Tables["Firmen"].Columns["ID_Firma"];
    firmsDataSet.Tables["Firmen"].PrimaryKey = keys;
    }
    .
    und hier schließlich das vermeindliche Datenbank Update:
    .
    try
    {

    string firmID = GetFirmID(oldName); // gibt mir den primary key der ausgewählten Firma, das funktioniert auch
    if (firmID != null)// && (CheckValues(newName)))
    {

    // die explizite Wertzuweisung an die Parameter würde ich mir SEHR gerne sparen
    // aber dann geht es nicht, Der DataAdapter holt sich nicht selbstständig die
    // neuen Werte aus dem DataSet
    firmsDataAdapter.UpdateCommand.Parameters["Name"].Value = newName;
    firmsDataAdapter.UpdateCommand.Parameters["Zusatz"].Value = newZusatz;
    firmsDataAdapter.UpdateCommand.Parameters["Ort"].Value = newOrt;
    firmsDataAdapter.UpdateCommand.Parameters["Postfach"].Value = newPostfach;
    firmsDataAdapter.UpdateCommand.Parameters["PLZ"].Value = newPLZ;
    firmsDataAdapter.UpdateCommand.Parameters["Straße"].Value = newStraße;
    firmsDataAdapter.UpdateCommand.Parameters["Tel_Nr"].Value = newTel;
    firmsDataAdapter.UpdateCommand.Parameters["Fax_Nr"].Value = newFax;
    firmsDataAdapter.UpdateCommand.Parameters["Mobil_Nr"].Value = newMobil;
    firmsDataAdapter.UpdateCommand.Parameters["E_Mail"].Value = newMail;
    firmsDataAdapter.UpdateCommand.Parameters["ID_Firma"].Value = firmID;

    .
    .
    if (firmsDataSet.HasChanges())
    MessageBox.Show("Bingo");
    firmsDataSet.WriteXml("FirmsDataSet");

    // hier kommt die Fehlermeldung, vorrausgesetzt das DataSet akzeptiert, das es geändert wurde
    firmsDataAdapter.Update(firmsDataSet, "Firmen");

    // dieser Befehl gibt keine Fehlermeldung, sondern aktualisiert die Datenbank
    //updateCom.ExecuteNonQuery();
    }
    catch ...


    Sorry für dieses überlage Post, aber ich hab alles reingehauen, wo der Fehler sein könnte.

    P.S.: Alles was mit _ anfängt ist eine Property. Der obige Code ist verteilt über die Klasse des GUIs und eine dazugehörende DB-Anbindungsklasse.

  • #2
    um nochmal die verschiedenen "Szenarien" zu nennen:
    .
    lasse ich diese Zeile
    .
    this.lstBx_Firmen.SelectedIndex = -1;
    .
    weg, und benutze diese
    .
    updateCom.ExecuteNonQuery();
    .
    für den Update zur Datenbank, kommen sie auch dort an.
    Das DataSet bekommt sie auch (in der XML Datei erscheinen sie), aber gleichzeitig bleibt das DataSet bei der Meinung, es wäre nicht geändert worden... ?!?!?
    .
    wenn ich andersherum diese Zeile
    .
    this.lstBx_Firmen.SelectedIndex = -1;
    .
    drinlasse, und den Update per
    .
    firmsDataAdapter.Update(firmsDataSet, "Firmen");
    .
    ausführe, bekomme ich die Fehlermeldung
    "ERROR [HY090] - Ungültige Zeichen oder Pufferlänge".
    .
    also irgendwo ist doch da gewaltig der Wurm drin.
    Warum weigert sich das DataSet, die Änderung, die es ja bekommt, als solche wahrzunehmen

    Comment


    • #3
      Hallo,

      immer dann, wenn Controls über den CurrencyManager an ein DataSet gebunden werden, kontrolliert der CurrencyManager den Zeitpunkt der Aktualisierung des DataSets. ADO.NET geht davon aus, dass der Inhalt des DataSets nur zu 2 Zeitpunkten aktualisiert wird:<br>
      1. Der CurrencyManager ändert seine Position (d.h. wechselt zu einem anderen Datensatz).<br>
      2. Programm ruft die CurrencyManager-Methode <b>EndCurrentEdit</b> auf.
      <br>
      Ich würde daher sicherstellen, dass vor dem Aufruf von <i>firmsDataAdapter.Update(firmsDataSet, "Firmen"); </i> die für die Datenbindung zuständige CurrencyManager-Methode EndCurrentEdit aufgerufen wird.
      <br>
      &gt;Wenn ich nun firmsDataSet.HasChanges() abfrage...
      Was passiert, wenn anstelle von HasChanges die Methode <b>GetChanges</b> aufgerufen wird? Enthält das zurückgelieferte DataSet den geänderten Datensatz

      Comment


      • #4
        vielen Dank für die Hilfe.
        Das mit EndCurrentEdit hatte ich schon woanders erfahren ( im Zusammenhang mit einem empfohlenen Wechsel von Odbc nach OleDb), das mit GetChanges werde ich gleich mal ausprobieren!

        Aber jetzt verstehe ich endlich wozu der Currency Manager da ist.
        Ich hatte irgendwie nur im Kopf, das er dazu da wäre, zwischen verschiedenen Bindings bzw DataSourcen "umzuschalten"..

        Comment


        • #5
          tja wenn ich es so mache:
          .

          this.BindingContext[myDataSet].EndCurrentEdit();
          DataSet test = myDataSet.GetChanges();
          test.WriteXml("test");
          .
          OleDbCommandBuilder cb = new OleDbCommandBuilder(myDataAdapter);
          UpLoadData();
          .

          dann bekomme ich eine NullReference Exception bei der test.Write... Zeile.
          Tja faszinierend, es will und will nicht funktionieren, die scheinbar einfachste Sache der Welt. Ich glaub ich werd langsam wahnsinnig..

          Comment


          • #6
            ich habs gefunden....
            Da ich ja ein untypisiertes DataSet benutze, ist mir eingefallen, das ich ja immer auch den Tabellennamen explizit angeben muss.
            Mache ich also
            this.BindingContext[myDataSet, "TabellenName"].EndCurrentEdit();
            klappt es.

            Unglaublich, wie einfach.
            Unglaublich, wie lange ich gebraucht hab das zu finden...

            Comment

            Working...
            X