none
Parallelitätsverletzung RRS feed

  • Frage

  • Hallo
     
    ich habe ein Schedule Control was über Databinding mit einer DataTable verbunden ist.
     
    Sobald ich im Control was ändere und ein Update auf den Adapter durchführe bekomme ich die unten stehende Meldung:
    {"Parallelitätsverletzung : Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt."}
     
    Was hat das zu bedeuten ? Kann mir jemand weiterhelfen, wie man das verhindert ?
     
    Danke
     
    Andreas
    Dienstag, 8. November 2011 11:43

Antworten

  • Hallo Andreas,

    da dass Problem bei neuen Datenzeilen auftritt:

    Wenn Du eine Tabelle mit Identitätswerten hast, so musst Du diese nach dem Einfügen getrennt abrufen,
    da Access keine Batchbefehle unterstützt und somit kein Abruf des von Access vergebenen Identitätswerts erfolgt. 

    Siehe dazu: Abrufen von Identitäts- oder AutoWert-Werten (ADO.NET)
    insbes. den Abschnitt "Abrufen von Microsoft Access-AutoWert-Werten".

    Es empfiehlt sich bei der DataTable mit negativem AutoIncrementStep zu arbeiten,
    damit keine Dopplungen auftreten (und man sieht, obe es sich um einen gespeicherten Satz handelt).

    Gruß Elmar

    Mittwoch, 9. November 2011 13:59
    Beantworter

Alle Antworten

  • Hallo Andreas Waning,

    Die aktuellste Version der Community Forums NNTP Bridge ist 2011-05-31, V44 (Stable): http://communitybridge.codeplex.com/releases/view/67354

    Deine Version ist Community Forums NNTP Server 1.1.40.0

    Grüße,

    Robert


    Dienstag, 8. November 2011 12:47
    Moderator
  • Hallo Andreas,

    die Ausnahme kommt, wenn durch die Kriterien des UpdateCommand keinen Datensatz aktualisiert wurde,
    siehe dazu Vollständige Parallelität (ADO.NET).

    Neben dem vorgesehen Fall, dass ein anderer Anwender den Datensatz aktualisiert hat,
    kann es in einigen Datenkonstellationen ungewollt dazu kommen,
    z. B. bei Gleitkommazahlen durch Ungenauigkeiten, die beim Konvertieren entstehen können.
    Oder auch wenn das Datenbankschema nicht mehr ganz zur DataTable passt.

    Überprüfe mal die Kriterien, die das UpdateCommand verwendet.

    Gruß Elmar

    Dienstag, 8. November 2011 14:25
    Beantworter
  • Hallo Andreas,

    Elmar hat Recht. Unter Umständen erzeugt der Visual Studio Designer beim Erstellen einer neuen Datenquelle einen UpdateCommand-String für die vollständige Parallelität, der mit der verwendeten Storage-Datenbank nicht kompatibel ist. Schau mal in der XSD-Datei oder im DataSet-Designer nach. 

    In diesem Fall empfiehlt sich, einfache Parallelität zu verwenden. Dazu ersetzt man im DataSet-Designer die beim Adapter erzeugte, ellenlange WHERE-Clause durch eine einfachere Variante, z.B. "WHERE (AppointmentID = ?)".

    Einen ähnlichen Fall (Parallelitätsverletzung mit Scheduling-Komponente) kannst Du hier finden:
    http://www.devexpress.com/Support/Center/p/Q250535.aspx

    Gruß
    Marcel

    Dienstag, 8. November 2011 16:47
    Moderator
  • Hallo MArcel,
     
    das mit der Where Abfrage habe ich gemacht. Klappt trotzdem nicht.
     
    Keine Ahnung was der da hat. Ich versuch mal Infragistics ran zuziehen vielleicht hat der eine Lösung.
     
    Danke,
    Andreas
     
     

    Hallo Andreas,

    Elmar hat Recht. Unter Umständen erzeugt der Visual Studio Designer beim Erstellen einer neuen Datenquelle einen UpdateCommand-String für die vollständige Parallelität, der mit der verwendeten Storage-Datenbank nicht kompatibel ist. Schau mal in der XSD-Datei oder im DataSet-Designer nach. 

    In diesem Fall empfiehlt sich, einfache Parallelität zu verwenden. Dazu ersetzt man im DataSet-Designer die beim Adapter erzeugte, ellenlange WHERE-Clause durch eine einfachere Variante, z.B. "WHERE (AppointmentID = ?)".

    Einen ähnlichen Fall (Parallelitätsverletzung mit Scheduling-Komponente) kannst Du hier finden:
    http://www.devexpress.com/Support/Center/p/Q250535.aspx

    Gru�?
    Marcel

    Dienstag, 8. November 2011 21:57
  • Hallo Andreas,

    das Steuerelement hat damit i. a. nichts zu tun -
    ausgenommen es arbeitet bei der Datenbindung unsauber.

    Die Antwort war wiederum nur sehr allgemein, da Du weder zur verwendeten Datenbank
    noch zum Tabellenschema und generierten UpdateCommand näheres gesagt hast.

    Wenn selbst das von Marcel vorgeschlagene Nur-PK-Update (Last-Wins) fehlschlägt,
    so wäre eine Frage: Welcher Datentyp haben die Primärschlüsselspalten?

    Wenn Du dazu mehr Infos hast, kann man das Problem eher einkreisen.

    Gruß Elmar

    Dienstag, 8. November 2011 22:44
    Beantworter
  • Hallo Elmar,
    danke für deine Hilfe.
     
    Dem Steuerelement wird ein Appointment zugewiesen. Das wird angezeigt und bei UpdateDatatable auch gespeichert. Nur wenn ich jetzt das Appointment verändere und dann versuche zu speichern
    kommt der Fehler. (Das hat nichts mit 2 Benutzer zutun.) Alle anderen Appointment, ausser dem neu zugefügten, kann ich speichern.
     
    Wenn ich die App neu starte, dann kann ich dieses Appointment verändern und speichern.
     
    Das Update habe ich so wie Marcel meinte mal abgeändert. (Where Appentmentid = ?)  Der Fehler tritt dann immer noch auf.
     
    Keine Ahnung was ich da noch machen soll.
     
    Danke für eure Hilfe,
    Andreas
     
     
     
     
     
     
    Hier die Tabelle: (Accesstabelle)
    AppointmentID ist der primary key vom typ int (Autowert)
     
    AppointmentID  AllProperties  StartDateTime                  EndDateTime               Subject                 AllDayEvent     OwnerKey
    1                                          02.11.2011     08:00:00     02.11.2011 10:00:00     Ortstermin1             Nein             AW
    2                                          02.11.2011     08:00:00     02.11.2011 09:45:00     Aktenbearbeitet        Nein             MW
    3                                          14.11.2011     08:00:00     14.11.2011 12:45:00     AW                         Nein             AW
    5                                          14.11.2011     13:00:00     14.11.2011 14:00:00     New Appointment     Nein             MW
     
     
     
     
    Hier das Update command:
     
         // Configure the UPDATE command
         OleDbCommand updateCommand = new OleDbCommand();
         commandTextTemplate = @"UPDATE {0} SET AllDayEvent = ?, AllProperties = ?, EndDateTime = ?, OwnerKey = ?, StartDateTime = ?, Subject = ? WHERE (AppointmentId = ?) AND (AllDayEvent = ?) AND (AllProperties = ? OR ? IS NULL AND AllProperties IS NULL) AND (EndDateTime = ?) AND (OwnerKey = ? OR ? IS NULL AND OwnerKey IS NULL) AND (StartDateTime = ?) AND (Subject = ? OR ? IS NULL AND Subject IS NULL)";
         updateCommand.CommandText = string.Format( commandTextTemplate, WinScheduleMSAccessSupport.APPOINTMENTS_TABLE_NAME );
         updateCommand.Connection = this.Connection;
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("AllDayEvent", System.Data.OleDb.OleDbType.Boolean, 2, "AllDayEvent"));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("AllProperties", System.Data.OleDb.OleDbType.VarBinary, 0, "AllProperties"));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("EndDateTime", System.Data.OleDb.OleDbType.DBTimeStamp, 0, "EndDateTime"));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("OwnerKey", System.Data.OleDb.OleDbType.VarWChar, 50, "OwnerKey"));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("StartDateTime", System.Data.OleDb.OleDbType.DBTimeStamp, 0, "StartDateTime"));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Subject", System.Data.OleDb.OleDbType.VarWChar, 50, "Subject"));
                            
         //updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("AppointmentId", System.Data.OleDb.OleDbType.Integer,0,"AppointmentId"));
     
                       
                           updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_AppointmentId", System.Data.OleDb.OleDbType.Integer, 0, System.Data.ParameterDirection.Input, false, ((System.Byte)(10)), ((System.Byte)(0)), "AppointmentId", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_AllDayEvent", System.Data.OleDb.OleDbType.Boolean, 2, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "AllDayEvent", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_AllProperties", System.Data.OleDb.OleDbType.VarBinary, 0, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "AllProperties", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_AllProperties1", System.Data.OleDb.OleDbType.VarBinary, 0, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "AllProperties", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_EndDateTime", System.Data.OleDb.OleDbType.DBTimeStamp, 0, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "EndDateTime", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_OwnerKey", System.Data.OleDb.OleDbType.VarWChar, 50, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "OwnerKey", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_OwnerKey1", System.Data.OleDb.OleDbType.VarWChar, 50, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "OwnerKey", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_StartDateTime", System.Data.OleDb.OleDbType.DBTimeStamp, 0, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "StartDateTime", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_Subject", System.Data.OleDb.OleDbType.VarWChar, 50, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Subject", System.Data.DataRowVersion.Original, null));
         updateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_Subject1", System.Data.OleDb.OleDbType.VarWChar, 50, System.Data.ParameterDirection.Input, false, ((System.Byte)(0)), ((System.Byte)(0)), "Subject", System.Data.DataRowVersion.Original, null));
                       
     
         this._oleDbDataAdapterForAppointments.UpdateCommand = updateCommand;
     
     
     
     
     

     

    Hallo Andreas,

    das Steuerelement hat damit i. a. nichts zu tun -
    ausgenommen es arbeitet bei der Datenbindung unsauber.

    Die Antwort war wiederum nur sehr allgemein, da Du weder zur verwendeten Datenbank
    noch zum Tabellenschema und generierten UpdateCommand näheres gesagt hast.

    Wenn selbst das von Marcel vorgeschlagene Nur-PK-Update (Last-Wins) fehlschlägt,
    so wäre eine Frage: Welcher Datentyp haben die Primärschlüsselspalten?

    Wenn Du dazu mehr Infos hast, kann man das Problem eher einkreisen.

    Gru�? Elmar

    Mittwoch, 9. November 2011 06:13
  • Hallo Andreas,

    Ich konnte das von dir gemeldete Verhalten mit der Scheduler-Komponente von Infragistics und einer Access-Datenbank beim besten Willen nicht nachvollziehen.

    Selbst bei Anwendung von vollständiger Parallelität funktionierte das Ändern und das erneute Speichern ohne Zwischenfälle. Schwer zu sagen, was bei dir anders ist (OleDB z.B. ist sehr empfindlich gegenüber positionellen Änderungen der Parameter).
    Nimm doch mal bitte die Standard-Demo (StartupSolution), die mit den WindowsForms-Komponenten von Infragistics kommt und binde z.B. das UltraDayView-Steuerelement an deine Access Datenbank. Teste ob folgender Code funktioniert:

            private void BindingDayView_Load(object sender, EventArgs e)
            {
                this.ultraCalendarInfo1.DataBindingsForAppointments.BindingContextControl = this;
                this.ultraCalendarInfo1.DataBindingsForAppointments.BindingContextControl = this;
    
                ds = new Data.schedulerDataSet();
                appointmentAdapter = new AppointmentTableAdapter();
                appointmentAdapter.Fill(ds.Appointment);
                
                // TODO:1. Set the DataSource and DataMember for Appointments using the SetDataBinding method
                this.ultraCalendarInfo1.DataBindingsForAppointments.SetDataBinding(ds, "Appointment");
                this.ultraCalendarInfo1.DataBindingsForOwners.SetDataBinding(ds, "Owner");
                
                // TODO:2. Set the properties for AppointmentsDataBinding and OwnersDataBinding objects
                this.ultraCalendarInfo1.DataBindingsForAppointments.StartDateTimeMember = "StartDateTime";
                this.ultraCalendarInfo1.DataBindingsForAppointments.EndDateTimeMember = "EndDateTime";
                this.ultraCalendarInfo1.DataBindingsForAppointments.SubjectMember = "Subject";
                this.ultraCalendarInfo1.DataBindingsForAppointments.OwnerKeyMember = "OwnerKey";
                this.ultraCalendarInfo1.DataBindingsForOwners.KeyMember = "OwnerKey";
                this.ultraCalendarInfo1.DataBindingsForOwners.NameMember = "Name";
                
                // TODO:3. Assign UltraCalendarInfo component to the CalendarInfo property of UltraDayView control.
                this.ultraDayView1.CalendarInfo = this.ultraCalendarInfo1;
    }
    


    Wenn Du noch immer Probleme hast, lade bitte das von dir modifizierte StartupSolution-Projekt z.B. auf SkyDrive hoch und poste hier einen Link.

    Es wird sich ganz bestimmt eine Lösung auch für dein Problem finden. Das wäre doch gelacht ;-)

    Gruß
    Marcel

    Mittwoch, 9. November 2011 12:38
    Moderator
  • Hallo Andreas,

    da dass Problem bei neuen Datenzeilen auftritt:

    Wenn Du eine Tabelle mit Identitätswerten hast, so musst Du diese nach dem Einfügen getrennt abrufen,
    da Access keine Batchbefehle unterstützt und somit kein Abruf des von Access vergebenen Identitätswerts erfolgt. 

    Siehe dazu: Abrufen von Identitäts- oder AutoWert-Werten (ADO.NET)
    insbes. den Abschnitt "Abrufen von Microsoft Access-AutoWert-Werten".

    Es empfiehlt sich bei der DataTable mit negativem AutoIncrementStep zu arbeiten,
    damit keine Dopplungen auftreten (und man sieht, obe es sich um einen gespeicherten Satz handelt).

    Gruß Elmar

    Mittwoch, 9. November 2011 13:59
    Beantworter
  • Hallo Elmar,

    Es ist sehr wahrscheinlich, dass Andreas in die von dir genannte Falle getappt ist. Wenn er einen vom Designer erstellten Adapter verwendet, steht die AppointmentID nach dem ersten Aufruf von Update() auf -N (z.B. -1), beim anschließenden Bearbeiten des gleichen Datensatzes und einem erneuten Aufruf von Update() wird die Parallelität verletzt, da natürlich kein Termin mit AppointmentID -1 gefunden werden kann.

    Gruß
    Marcel

    Mittwoch, 9. November 2011 16:09
    Moderator
  • Hallo MArcel
     
    ich werde das heute Abend oder morgen testen.
     
    Erstmal danke,
    Andreas

    Hallo Andreas,

    Ich konnte das von dir gemeldete Verhalten mit der Scheduler-Komponente von Infragistics und einer Access-Datenbank beim besten Willen nicht nachvollziehen.

    Selbst bei Anwendung von vollständiger Parallelität funktionierte das �?ndern und das erneute Speichern ohne Zwischenfälle. Schwer zu sagen, was bei dir anders ist (OleDB z.B. ist sehr empfindlich gegenüber positionellen �?nderungen der Parameter).
    Nimm doch mal bitte die Standard-Demo (StartupSolution), die mit den WindowsForms-Komponenten von Infragistics kommt und binde z.B. das UltraDayView-Steuerelement an deine Access Datenbank. Teste ob folgender Code funktioniert:

            private void BindingDayView_Load(object sender, EventArgs e)
            {
                this.ultraCalendarInfo1.DataBindingsForAppointments.BindingContextControl = this;
                this.ultraCalendarInfo1.DataBindingsForAppointments.BindingContextControl = this;
    
                ds = new Data.schedulerDataSet();
                appointmentAdapter = new AppointmentTableAdapter();
                appointmentAdapter.Fill(ds.Appointment);
                
                // TODO:1. Set the DataSource and DataMember for Appointments using the SetDataBinding method
                this.ultraCalendarInfo1.DataBindingsForAppointments.SetDataBinding(ds, "Appointment");
                this.ultraCalendarInfo1.DataBindingsForOwners.SetDataBinding(ds, "Owner");
                
                // TODO:2. Set the properties for AppointmentsDataBinding and OwnersDataBinding objects
                this.ultraCalendarInfo1.DataBindingsForAppointments.StartDateTimeMember = "StartDateTime";
                this.ultraCalendarInfo1.DataBindingsForAppointments.EndDateTimeMember = "EndDateTime";
                this.ultraCalendarInfo1.DataBindingsForAppointments.SubjectMember = "Subject";
                this.ultraCalendarInfo1.DataBindingsForAppointments.OwnerKeyMember = "OwnerKey";
                this.ultraCalendarInfo1.DataBindingsForOwners.KeyMember = "OwnerKey";
                this.ultraCalendarInfo1.DataBindingsForOwners.NameMember = "Name";
                
                // TODO:3. Assign UltraCalendarInfo component to the CalendarInfo property of UltraDayView control.
                this.ultraDayView1.CalendarInfo = this.ultraCalendarInfo1;
    }
    


    Wenn Du noch immer Probleme hast, lade bitte das von dir modifizierte StartupSolution-Projekt z.B. auf SkyDrive hoch und poste hier einen Link.

    Es wird sich ganz bestimmt eine Lösung auch für dein Problem finden. Das wäre doch gelacht ;-)

    Gru�?
    Marcel

    Mittwoch, 9. November 2011 16:10
  • Hallo Elmar,
    erstmal danke,
     
    ich schaue mir das später in ruhe an.

    Hallo Andreas,

    da dass Problem bei neuen Datenzeilen auftritt:

    Wenn Du eine Tabelle mit Identitätswerten hast, so musst Du diese nach dem Einfügen getrennt abrufen,
    da Access keine Batchbefehle unterstützt und somit kein Abruf des von Access vergebenen Identitätswerts erfolgt. 

    Siehe dazu: Abrufen von Identitäts- oder AutoWert-Werten (ADO.NET)
    insbes. den Abschnitt "Abrufen von Microsoft Access-AutoWert-Werten".

    Es empfiehlt sich bei der DataTable mit negativem AutoIncrementStep zu arbeiten,
    damit keine Dopplungen auftreten (und man sieht, obe es sich um einen gespeicherten Satz handelt).

    Gru�? Elmar

    Mittwoch, 9. November 2011 16:10
  • Hast du den Infragistcs Form 11.1 ?
    Ich würde dir das dann auf dropbox legen, so das du das laden kannst.
     
    Hier beim Kunden kann ich leider kein Dropbox !!!

    Hallo Elmar,

    Es ist sehr wahrscheinlich, dass Andreas in die von dir genannte Falle getappt ist. Wenn er einen vom Designer erstellten Adapter verwendet, steht die AppointmentID nach dem ersten Aufruf von Update() auf -N (z.B. -1), beim anschlie�?enden Bearbeiten des gleichen Datensatzes und einem erneuten Aufruf von Update() wird die Parallelität verletzt, da natürlich kein Termin mit AppointmentID -1 gefunden werden kann.

    Gru�?
    Marcel

    Mittwoch, 9. November 2011 16:42
  • Hallo Andreas,

    > Hast du den Infragistcs Form 11.1?
    Ja

    > Ich würde dir das dann auf dropbox legen, so das du das laden kannst.
    Poste bitte den Link dazu.

    Gruß
    Marcel

    Mittwoch, 9. November 2011 18:34
    Moderator
  • Da bin ich ja mal gespannt ob dir dazu was einfällt.
     
    Im Menu Data -> Save kannst du ein Update ausführen. (Hab ich hinzugefügt)
     
    Gehe folgendermassen vor:
     
    -lege ein neues Appointment an. (Click in Slot)
    -Speiche im Menu Save
    -ändere die Zeit durch ziehen des Slots.
    -Speiche wieder.
     
    Irgendwann bekommt zu eine Fehlermeldung. Dann kann dieses Appointment nicht mehr gespeichert werden.
     
    Danke,
    Andreas
     
     
     
     
     
     
     
     

    Hallo Andreas,

    > Hast du den Infragistcs Form 11.1?
    Ja

    > Ich würde dir das dann auf dropbox legen, so das du das laden kannst.
    Poste bitte den Link dazu.

    Gru�?
    Marcel

    Mittwoch, 9. November 2011 21:34
  • Hallo Marcel,
     
    was ich vergessen hatte. Die Accessdatei liegt im DebugVerzeichnis. Du brauchst nur das File entpacken. Du brauchst nichts an Pathen einstellen.
     
    Bin mal gespannt was du da rausfindest.
     
    Danke,
    Andreas
     

     

    Hallo Andreas,

    > Hast du den Infragistcs Form 11.1?
    Ja

    > Ich würde dir das dann auf dropbox legen, so das du das laden kannst.
    Poste bitte den Link dazu.

    Gru�?
    Marcel

    Donnerstag, 10. November 2011 07:10
  • Hallo Andreas,

    > Bin mal gespannt was du da rausfindest.

    Herausgefunden habe ich das, was Elmar bereits vermutet hatte ;-)

    AppointmentID ist NULL nach dem ersten Speichern des Datensatzes. Wenn Du nun den Datensatz bearbeitest, ändert sich dessen Status auf DataRowState.Modified. Beim erneuten Speichern versucht der Adapter wg. dem vorhandenen UpdateCommand ("UPDATE Appointments [...] WHERE (AppointmentId = ?)") einen Datensatz mit AppointmentID=NULL zu finden (das steht nämlich unter row[0, DataRowVersion.Original]), was angesichts des zwischenzeitlich autoinkrementierten Feldes natürlich fehlschlägt: AppointmentID hat nun in Access einen inkrementierten Zahlenwert und hat nur auf .NET-Seite noch einen NULL-Wert.

    Was tun? - Das, was Elmar schon vorgeschlagen hat, bzw. was in Elmar's Link bezügl. Microsoft Access vorgeschlagen wird:

    - Adapter.Update() nur mit den tatsächlichen Änderungen aufrufen
    - das RowUpdated-Ereignis abonnieren
    - im RowUpdated-Handler, nach dem Insert des neuen Datensatzes, gleich die AppointmentID abfragen und in die Zeile schreiben
    - die DataTable mit den tatsächlichen Änderungen mit der Appointments-Tabelle "mergen".

    Das Ganze hat nur einen Haken: Das Zusammenführen der Tabellen (Änderungstabelle, Termintabelle) würde nicht klappen, und plötzlich stünde der eben über Insert eingefügte Datensatz zweimal in der UI da, einmal mit AppointmentID NULL und einmal mit der tatsächlichen AppointmentID, die Access vergeben hat und die wir im RowUpdated-Handler abgefragt haben.

    Warum aber funktioniert DataTable.Merge() nicht? - Weil die Appointments-Tabelle keinen Primärschlüssel hat und keine AutoIncrement-Eigenschaften definiert wurden. Aus der Dokumentation:

    Beim Zusammenführen einer neuen Quell-DataTable mit dem Ziel werden Quellzeilen mit dem DataRowState-Wert Unchanged, Modified oder Deleted mit den Zielzeilen zusammengeführt, die dieselben Primärschlüsselwerte enthalten.

    Das kann aber nachgeholt werden. Am einfachsten, indem man das Schema manuell abruft (man könnte freilich auch Tabellen-Mappings verwenden und den PrimaryKey manuell definieren):

    // Infragistics.Win.UltraWinSchedule.Samples.WinScheduleDatabaseSupportBase-Klasse
    
    public DataSet DataSet
    {
       //[...]
       dataAdapter = this.DataAdapterForAppointments;
       dataAdapter.FillSchema(this._dataSet, SchemaType.Source, WinScheduleDatabaseSupportBase.APPOINTMENTS_TABLE_NAME);
       DataColumn appointmentIdColumn = this.Appointments.Columns[0];
       appointmentIdColumn.AutoIncrementSeed = -1;
       appointmentIdColumn.AutoIncrementStep = -1;
    
       dataAdapter.Fill( this._dataSet, WinScheduleDatabaseSupportBase.APPOINTMENTS_TABLE_NAME );
    
       //[...]
      return this._dataSet;
    }
    
    
    

    Also erst richten wir uns die Tabelle so ein, wie wir sie haben wollen, und erst dann rufen wir die Daten ab. Alles andere ist eine einfache Copy-and-Paste-Aktion aus der MSDN-Dokumentation:

    public void UpdateAppointmentsTable() {
        if ( this.HasAppointmentChanges == false )
            return;
    
        try {
            long hierWirdUpgedatet;
    
            DataTable appointmentsTable = this.DataSet.Tables[WinScheduleMSSQLServerSupport.APPOINTMENTS_TABLE_NAME];
            DataTable appointmentChanges = appointmentsTable.GetChanges();
            this.DataAdapterForAppointments.RowUpdated += new OleDbRowUpdatedEventHandler(Adapter_RowUpdated);
            this.DataAdapterForAppointments.Update(appointmentChanges);
            appointmentsTable.Merge(appointmentChanges);
            appointmentsTable.AcceptChanges();
        } catch(Exception ee) {
            MessageBox.Show(string.Format("DB Error = {0}",ee.Message));
        }
    
        this._hasAppointmentChanges = false;
    }
    
    void Adapter_RowUpdated(object sender, OleDbRowUpdatedEventArgs e) {
        if (e.StatementType == StatementType.Insert) {
            OleDbCommand cmdNewID = new OleDbCommand("SELECT @@IDENTITY", this.Connection);
            e.Row["AppointmentID"] = (int)cmdNewID.ExecuteScalar();
            e.Status = UpdateStatus.SkipCurrentRow;
        }
    }
    
    

     

    Gruß
    Marcel


    Donnerstag, 10. November 2011 10:26
    Moderator
  • Ha , wie schön das es Leute gibt, die richtig Ahnung haben. (Werd ich ja richtig Neidisch)
     
    Vielen Dank Marcel und Danke an Elmar.
     
    Gru�?
    Andreas
     
    PS: Jetzt muss ich erstmal Infragistics zusammen scheissen, das die ein Fehlerhaftes Sample ausliefern.......
     
     

     
     

    Hallo Andreas,

    > Bin mal gespannt was du da rausfindest.

    Herausgefunden habe ich das, was Elmar bereits vermutet hatte ;-)

    AppointmentID ist NULL nach dem ersten Speichern des Datensatzes. Wenn Du nun den Datensatz bearbeitest, ändert sich dessen Status auf DataRowState.Modified. Beim erneuten Speichern versucht der Adapter wg. dem vorhandenen UpdateCommand ("UPDATE Appointments [...] WHERE (AppointmentId = ?)") einen Datensatz mit AppointmentID=NULL zu finden (das steht nämlich unter row[0, DataRowVersion.Original]), was angesichts des zwischenzeitlich autoinkrementierten Feldes natürlich fehlschlägt: AppointmentID hat nun in Access einen inkrementierten Zahlenwert und hat nur auf .NET-Seite noch einen NULL-Wert.

    Was tun? - Das, was Elmar schon vorgeschlagen hat, bzw. was in Elmar's Link bezügl. Microsoft Access vorgeschlagen wird:

    - Adapter.Update() nur mit den tatsächlichen �?nderungen aufrufen
    - das RowUpdated-Ereignis abonnieren
    - im RowUpdated-Handler, nach dem Insert des neuen Datensatzes, gleich die AppointmentID abfragen und in die Zeile schreiben
    - die DataTable mit den tatsächlichen �?nderungen mit der Appointments-Tabelle "mergen".

    Das Ganze hat nur einen Haken: Das Zusammenführen der Tabellen (�?nderungstabelle, Termintabelle) würde nicht klappen, und plötzlich stünde der eben über Insert eingefügte Datensatz zweimal in der UI da, einmal mit AppointmentID NULL und einmal mit der tatsächlichen AppointmentID, die Access vergeben hat und die wir im RowUpdated-Handler abgefragt haben.

    Warum aber funktioniert DataTable.Merge() nicht? - Weil die Appointments-Tabelle keinen Primärschlüssel hat und keine AutoIncrement-Eigenschaften definiert wurden. Aus der Dokumentation:

    Beim Zusammenführen einer neuen Quell-DataTable mit dem Ziel werden Quellzeilen mit dem DataRowState-Wert Unchanged, Modified oder Deleted mit den Zielzeilen zusammengeführt, die dieselben Primärschlüsselwerte enthalten.

    Das kann aber nachgeholt werden. Am einfachsten, indem man das Schema manuell abruft (man könnte freilich auch Tabellen-Mappings verwenden und den PrimaryKey manuell definieren):

    // Infragistics.Win.UltraWinSchedule.Samples.WinScheduleDatabaseSupportBase-Klasse
    
    public DataSet DataSet
    {
       //[...]
       dataAdapter = this.DataAdapterForAppointments;
       dataAdapter.FillSchema(this._dataSet, SchemaType.Source, WinScheduleDatabaseSupportBase.APPOINTMENTS_TABLE_NAME);
       DataColumn appointmentIdColumn = this.Appointments.Columns[0];
       appointmentIdColumn.AutoIncrementSeed = -1;
       appointmentIdColumn.AutoIncrementStep = -1;
    
       dataAdapter.Fill( this._dataSet, WinScheduleDatabaseSupportBase.APPOINTMENTS_TABLE_NAME );
    
       //[...]
      return this._dataSet;
    }
    
    
    

    Also erst richten wir uns die Tabelle so ein, wie wir sie haben wollen, und erst dann rufen wir die Daten ab. Alles andere ist eine einfache Copy-and-Paste-Aktion aus der MSDN-Dokumentation:

    public void UpdateAppointmentsTable() {
        if ( this.HasAppointmentChanges == false )
            return;
    
        try {
            long hierWirdUpgedatet;
    
            DataTable appointmentsTable = this.DataSet.Tables[WinScheduleMSSQLServerSupport.APPOINTMENTS_TABLE_NAME];
            DataTable appointmentChanges = appointmentsTable.GetChanges();
            this.DataAdapterForAppointments.RowUpdated += new OleDbRowUpdatedEventHandler(Adapter_RowUpdated);
            this.DataAdapterForAppointments.Update(appointmentChanges);
            appointmentsTable.Merge(appointmentChanges);
            appointmentsTable.AcceptChanges();
        } catch(Exception ee) {
            MessageBox.Show(string.Format("DB Error = {0}",ee.Message));
        }
    
        this._hasAppointmentChanges = false;
    }
    
    void Adapter_RowUpdated(object sender, OleDbRowUpdatedEventArgs e) {
        if (e.StatementType == StatementType.Insert) {
            OleDbCommand cmdNewID = new OleDbCommand("SELECT @@IDENTITY", this.Connection);
            e.Row["AppointmentID"] = (int)cmdNewID.ExecuteScalar();
            e.Status = UpdateStatus.SkipCurrentRow;
        }
    }
    
    

     

    Gru�?
    Marcel


    Donnerstag, 10. November 2011 11:54
  • Hallo Andreas,

    Schön dass wir dir helfen konnten.

    Gruß
    Marcel

    Donnerstag, 10. November 2011 15:47
    Moderator
  • Hallo Andreas Waning,

    Ich möchte Dich bitte folgendes lesen und die Beiträge die Dir geholfen haben zu bewerten.

    Vielen Dank.

    Nutzen Sie die Bewertungsfunktionen ("Antwort" und "Hilfreich") in denMSDN Foren! Unter anderem können andere später eine Lösung schneller finden. Es ist also wünschenswert, dass die fragenden (Benutzer) die Postings/Beiträge anderer Beantworter bewerten.
    Hier dazu die wichtigsten Anhaltspunkte aus den Forenregeln und FAQs.


    Lösungsbeiträge als „Die Antwort“ markieren
    Bitte markieren Sie den Beitrag, der zur Lösung geführt hat, als "Die Antwort". Durch Bewerten eines Beitrags als "Die Antwort" können andere Teilnehmer die Lösung schneller finden. Außerdem können Sie dem Benutzer, der die Antwort eingereicht hat, für seinen Beitrag danken und zur Steigerung der Antwortqualität in der Diskussionsgruppe beitragen.
    [Quelle: Forenregeln]

    Wie bewerte ich einen Beitrag? Um einen Beitrag als hilfreich zu bewerten, klicken Sie in einem beliebigen Beitrag auf Als hilfreich bewerten. Sie können Ihre Stimme nur einmal für einen Beitrag abgeben.
    [Quelle: Häufig gestellte Fragen]

    Grüße,

    Robert


    Donnerstag, 10. November 2011 17:05
    Moderator
  • Hallo Robert,
     
    1. ich habe meine Bridge Software upgedatet. Woran kannst du sehen, dass ich eine veraltete Version verwendet habe ?
     
    2. Für Bewertungen muss ich wahrscheinlich auf die Msdn Seite gehen, oder ?
       (Da sollte sich Microsoft was einfallen lassen, dass das alles etwas komfortabler geht. Einloggen, Forum wählen, Beitrag suchen usw...)
     
    Diesen Beitrag werde ich in Kürze bewerten.
     
    Danke an alle,
    Andreas
     
     
     

    Hallo Andreas Waning,

    Ich möchte Dich bitte folgendes lesen und die Beiträge die Dir geholfen haben zu bewerten.

    Vielen Dank.

    Nutzen Sie die Bewertungsfunktionen ("Antwort" und "Hilfreich") in denMSDN Foren! Unter anderem können andere später eine Lösung schneller finden. Es ist also wünschenswert, dass die fragenden (Benutzer) die Postings/Beiträge anderer Beantworter bewerten.
    Hier dazu die wichtigsten Anhaltspunkte aus den Forenregeln und FAQs.


    Lösungsbeiträge als �??Die Antwort�?? markieren
    Bitte markieren Sie den Beitrag, der zur Lösung geführt hat, als "Die Antwort". Durch Bewerten eines Beitrags als "Die Antwort" können andere Teilnehmer die Lösung schneller finden. Au�?erdem können Sie dem Benutzer, der die Antwort eingereicht hat, für seinen Beitrag danken und zur Steigerung der Antwortqualität in der Diskussionsgruppe beitragen.
    [Quelle: Forenregeln]

    Wie bewerte ich einen Beitrag? Um einen Beitrag als hilfreich zu bewerten, klicken Sie in einem beliebigen Beitrag auf Als hilfreich bewerten. Sie können Ihre Stimme nur einmal für einen Beitrag abgeben.
    [Quelle: Häufig gestellte Fragen]

    Grü�?e,

    Robert


    Freitag, 11. November 2011 05:45
  • 1. ich habe meine Bridge Software upgedatet. Woran kannst du sehen, dass ich eine veraltete Version verwendet habe ?

    Hallo Andreas Waning,

    Man kann die Version sehen wenn man in einem Beitrag auf Bearbeiten klickt (man muss auf die MSDN Web-Seite gehen) und dann am Ende des Beitrages ein kleines Anchor Zeichen sieht. Wenn man mit der Mouse über dieses Anchor Zeichen geht wird z.B. Microsoft Windows Live Mail 14.0.8089.726 via Community Forums NNTP Server 1.1.44.0 angezeigt…also man sieht den Client und die Version der Community Forums NNTP Bridge.

    2. Für Bewertungen muss ich wahrscheinlich auf die Msdn Seite gehen, oder ?

     Genau. Man muss auf die MSDN Web-Seite gehen.

    Diesen Beitrag werde ich in Kürze bewerten.

     

    Vielen Dank.

    Grüße,

    Robert

    Freitag, 11. November 2011 08:32
    Moderator
  • Hallo Andreas Waning,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert

    Mittwoch, 16. November 2011 10:26
    Moderator