Announcement

Collapse
No announcement yet.

Fehlermeldung: Objekt war geöffnet

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

  • Fehlermeldung: Objekt war geöffnet

    Hallo,<p>
    bei einem TAdoDataset.Edit bekomme ich folgende Fehlermeldung: <i>Exception der Klasse EOleException. Meldung: 'Das Objekt war geöffnet'</i><p>
    Hat jemand vielleicht eine Ahnung, wo die Fehlermeldung herrühren könnte? Das AdoDataset enthält eine Select Abfrage und ist zum Versuch der Abfrage laut Debugger im Browse-Modus.<p>
    Schöne Grüße, Mario Noack
    Schöne Grüße, Mario

  • #2
    .. ich habe es etwas einschränken können:<br>
    Ich habe eine Master-Detailbeziehung. Wenn ich in der Detailtabelle Änderungen speichere und dann die Mastertabelle Editieren will, kommt der Fehler. Schliesse ich vor dem Editieren der Mastertabelle die Detailtabelle, geht es problemlos.<p>
    Damit weiß ich zwar, wie ich das Problem umschiffen kann, aber ob mir das dauerhaft hilft, weiß ich nicht.<p>
    Schöne Grüße, Mario Noac
    Schöne Grüße, Mario

    Comment


    • #3
      <p><font face="Courier New, Courier, mono">object Form1: TForm1<br>
      Left = 227<br>
      Top = 107<br>
      Width = 870<br>
      Height = 640<br>
      Caption = 'Form1'<br>
      Color = clBtnFace<br>
      Font.Charset = DEFAULT_CHARSET<br>
      Font.Color = clWindowText<br>
      Font.Height = -11<br>
      Font.Name = 'MS Sans Serif'<br>
      Font.Style = []<br>
      OldCreateOrder = False<br>
      PixelsPerInch = 96<br>
      TextHeight = 13<br>
      object DBGrid1: TDBGrid<br>
      Left = 255<br>
      Top = 3<br>
      Width = 577<br>
      Height = 274<br>
      DataSource = DataSource1<br>
      TabOrder = 0<br>
      TitleFont.Charset = DEFAULT_CHARSET<br>
      TitleFont.Color = clWindowText<br>
      TitleFont.Height = -11<br>
      TitleFont.Name = 'MS Sans Serif'<br>
      TitleFont.Style = []<br>
      end<br>
      object DBGrid2: TDBGrid<br>
      Left = 261<br>
      Top = 285<br>
      Width = 581<br>
      Height = 327<br>
      DataSource = DataSource2<br>
      TabOrder = 1<br>
      TitleFont.Charset = DEFAULT_CHARSET<br>
      TitleFont.Color = clWindowText<br>
      TitleFont.Height = -11<br>
      TitleFont.Name = 'MS Sans Serif'<br>
      TitleFont.Style = []<br>
      end<br>
      object DBNavigator1: TDBNavigator<br>
      Left = 6<br>
      Top = 3<br>
      Width = 240<br>
      Height = 25<br>
      DataSource = DataSource1<br>
      TabOrder = 2<br>
      end<br>
      object DBNavigator2: TDBNavigator<br>
      Left = 12<br>
      Top = 291<br>
      Width = 240<br>
      Height = 25<br>
      DataSource = DataSource2<br>
      TabOrder = 3<br>
      end<br>
      object Button1: TButton<br>
      Left = 96<br>
      Top = 432<br>
      Width = 75<br>
      Height = 25<br>
      Caption = 'Button1'<br>
      TabOrder = 4<br>
      OnClick = Button1Click<br>
      end<br>
      object ADOConnection1: TADOConnection<br>
      Connected = True<br>
      ConnectionString = <br>
      'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' +<br>
      'fo=False;Initial Catalog=Northwind;Data Source=<font color="#FF0000"><b>ntsql</b></font>'<br>
      LoginPrompt = False<br>
      Provider = 'SQLOLEDB.1'<br>
      Left = 12<br>
      Top = 27<br>
      end<br>
      object ADODataSet1: TADODataSet<br>
      Active = True<br>
      Connection = ADOConnection1<br>
      CursorLocation = clUseServer<br>
      CommandText = 'select * from Orders'<br>
      Parameters = &lt;&gt;<br>
      Left = 45<br>
      Top = 27<br>
      end<br>
      object ADODataSet2: TADODataSet<br>
      Active = True<br>
      Connection = ADOConnection1<br>
      CursorLocation = clUseServer<br>
      CommandText = 'select * from [Order Details]'#13#10'where OrderID=:ORDERID'<br>
      DataSource = DataSource1<br>
      MasterFields = 'ORDERID'<br>
      Parameters = &lt;<br>
      item<br>
      Name = 'ORDERID'<br>
      Attributes = [paSigned]<br>
      DataType = ftInteger<br>
      Precision = 10<br>
      Value = 10260<br>
      end&gt;<br>
      Left = 42<br>
      Top = 60<br>
      end<br>
      object DataSource1: TDataSource<br>
      DataSet = ADODataSet1<br>
      Left = 75<br>
      Top = 27<br>
      end<br>
      object DataSource2: TDataSource<br>
      DataSet = ADODataSet2<br>
      Left = 75<br>
      Top = 60<br>
      end<br>
      end </font></p>
      &#10
      Schöne Grüße, Mario

      Comment


      • #4
        <p><font face="Courier New, Courier, mono">unit Unit1;</font></p>
        <p><font face="Courier New, Courier, mono">interface</font></p>
        <p><font face="Courier New, Courier, mono">uses<br>
        Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br>
        Dialogs, Grids, DBGrids, DB, ADODB, ExtCtrls, DBCtrls, StdCtrls;</font></p>
        <p><font face="Courier New, Courier, mono">type<br>
        TForm1 = class(TForm)<br>
        ADOConnection1: TADOConnection;<br>
        ADODataSet1: TADODataSet;<br>
        ADODataSet2: TADODataSet;<br>
        DataSource1: TDataSource;<br>
        DataSource2: TDataSource;<br>
        DBGrid1: TDBGrid;<br>
        DBGrid2: TDBGrid;<br>
        DBNavigator1: TDBNavigator;<br>
        DBNavigator2: TDBNavigator;<br>
        Button1: TButton;<br>
        procedure Button1Click(Sender: TObject);<br>
        private<br>
        { Private-Deklarationen }<br>
        public<br>
        { Public-Deklarationen }<br>
        end;</font></p>
        <p><font face="Courier New, Courier, mono">var<br>
        Form1: TForm1;</font></p>
        <p><font face="Courier New, Courier, mono">implementation</font></p>
        <p><font face="Courier New, Courier, mono">{$R *.dfm}</font></p>
        <p><font face="Courier New, Courier, mono">procedure TForm1.Button1Click(Sender:
        TObject);<br>
        begin<br>
        <font color="#FF0000">ADODataSet2.Append;<br>
        ADODataSet2.FieldByName('ProductID').Value := '43';<br>
        ADODataSet2.Post;</font></font></p>
        <p><font face="Courier New, Courier, mono" color="#FF0000"> ADODataSet2.Locate('PRODUCTID','11',[]);</font></p>
        <p><font face="Courier New, Courier, mono" color="#FF0000">// ADODataSet2.Close;<br>
        // ADODataSet2.Open;</font></p>
        <p><font face="Courier New, Courier, mono" color="#FF0000"> ADODataSet1.Edit;</font><font face="Courier New, Courier, mono"><br>
        end;</font></p>
        <p><font face="Courier New, Courier, mono">end.</font></p>
        <p>&nbsp;</p>
        <p>So, nun habe ich das Problem an der Datenbank <b>Northwind</b> vom SQL2000
        Server von MS endlich reproduzieren k&ouml;nnen. W&auml;re echt nett, wenn mir
        dass mal jemand gedanklich nachvollziehen k&ouml;nnte. Es m&uuml;sste eigentlich
        im DFM-Source nur der Server ge&auml;ndert werden, auf den tats&auml;chlich
        vorhandenen Servernamen.</p>
        <p>Gedacht hatte ich es mir eigentlich so: Detailsatz wird angelegt und dann wird
        auf einen (im allgemein den gerade angelegten) Datensatz positioniert. Das ganze
        geschieht mit <b>Locate </b>und genau das ist das Problem. Wird Locate weggelassen,
        funzt alles wunderbar. Ansonsten kommt halt die abstruse Fehlermeldung. Das Problem kommt bei mir unter Win2k SP2 mit Ado 2.6 und Ado 2.7 sowohl unter D5 sowie D6.</p>
        <p>Vielen Dank schon mal f&uuml;r Eure M&uuml;hen, Mario Noack</p&gt
        Schöne Grüße, Mario

        Comment


        • #5
          <font face="Courier New, Courier, mono"> type<br>
          &nbsp;TMyAdoDataSet = Class(TAdoDataSet)<br>
          END; </font>
          <p><font face="Courier New, Courier, mono">procedure TForm1.Button1Click(Sender:
          TObject);<br>
          begin<br>
          ADODataSet2.Append;<br>
          ADODataSet2.FieldByName('ProductID').Value := '43';<br>
          ADODataSet2.Post;</font></p>
          <p><font face="Courier New, Courier, mono"> ADODataSet2.Locate('PRODUCTID','11',[]);<br>
          <b><font color="#FF0000">TMyAdoDataSet(ADODataSet2).Destroy LookupCursor;</font></b></font></p>
          <p><font face="Courier New, Courier, mono"> ADODataSet1.Edit;<br>
          end;<br>
          </font> </p>
          <p>So geht's!! Aber dass das in D5 und D6 vergessen wurde, glaube ich fast nicht,
          wei&szlig; jemand vielleicht, ob ich nur eine falsche Herangehensweise an den
          Tag lege?</p>
          <p>Sch&ouml;ne Gr&uuml;&szlig;e, Mario Noack</p&gt
          Schöne Grüße, Mario

          Comment


          • #6
            Hallo,

            das Grundproblem liegt an der Konfiguration <b>clUseServer</b> für die TADODataSet-Komponenten. Beide Komponenten fordern einen Server-seitigen Cursor über die gleiche TADOConnection-Verbindung an. Bei einem Client-seitigen Cursor (clUseClient) trennt ADO den nativen Datenbank-Cursor sofort wieder, nachdem alle Datensätze der Ergebnismenge beim Öffnen sofort zum Client transportiert wurden. Die Datenbankverbindung ist danach sofort wieder "frei", so dass andere Aktionen völlig ohne Kollisionsrisiko über die gleiche Verbindung ausgeführt werden dürfen.

            Bei der Konfiguration clUseServer muss man hingegen damit rechnen, dass die Datenbankverbindung für längere Zeit blockiert bleibt und somit keine andere Aktion zulässig ist. Wenn eine Anwendung mehrere Datenmengen öffnen, die die Einstellungen server-seitiger Cursor, Forward-Only und Read-Only (Firehouse-Cursor) verwenden, so wird nur die erste Datenmenge über die Connection-Instanz verwaltet. Für alle anderen Datenmengen erstellt ADO <b>automatisch</b> im Hintergrund zusätzliche Verbindungen. Dies ist in dem o.g. Beispiel jedoch nicht der Fall (Locktyp = ltOptimistic) - daher auch das Problem. Microsoft hat dazu in seiner Knowlegde Base den Artikel Q235282 "INFO: SQL Server Spawns Additional Connections When You Open Multiple ForwardOnly ADO Recordsets" veröffentlicht.

            &gt;Das ganze geschieht mit Locate und genau das ist das Problem.

            Auf Locate würde ich sowieso generell bei ADO verzichten - denn hinter Locate steckt keine native ADO-Methode, sondern Borland verzweigt innerhalb der Locate-Methode entweder zu <b>Find</b> oder zu <b>Filter</b>. Es ist daher besser und effektiver, gleich eine der beiden Methoden zu verwenden - zumal wir dann entscheiden können, welcher Suchweg im Einzelfall besser ist.

            P.S: Für ADO gilt die folgende Fausregel für die Eigenschaft CursorLocation: <br>
            - MS ACCESS-Datenbank: <b>clUseServer</b> <br>
            - MS SQL Server-Datenbank: <b>clUseClient</b>
            &#10

            Comment


            • #7
              Hallo Andreas,<p>
              ganz verstehe ich das noch nicht, wir verwenden eigentlich einen <b>ctKeyset</b> Cursor. Zudem bezieht sich Q235282 auch nur auf SQL 6.5 und 7.0. Aber das muss ja nichts heißen, 8.0 wird ja auch nicht explizit ausgeschlossen. Auf alle Fälle kommt <b>clUseClient</b> aus verschiedenen Gründen im Moment leider nicht in Frage.<p>
              Aber hier noch eine Frage: Ich kann zwar mit der nativen Methode <b>Find</b> suchen, jedoch wie positioniere ich dann meine Table bzw. DataSource nach. Diese ist ja für die Visualisierung unverzichtbar? Kannst Du da vielleicht mal ein Beispiel machen?<p>
              Vielen Dank, Mario Noac
              Schöne Grüße, Mario

              Comment


              • #8
                Hallo,

                &gt;...wie positioniere ich dann meine Table bzw. DataSource nach?

                Das Recordset-Objekt stellt die Methode Find zur Verfügung, um einen bestimmten Datensatz in der Ergebnismenge lokalisieren zu können. Diese Methode steht bei client-seitigen Cursors (clUseClient) immer zur Verfügung und bei den serverseitigen Cursors nur dann, wenn die restlichen Konfigurationen die Unterstützung von Bookmarks erlauben. Immer dann, wenn Find bei clientseitigen Cursorn aufgerufen wird, erzeugt ADO über die OLE DB Client Cursor Engine einen internen Index für das Feld, das in dem Suchbegriff referenziert wird. Aus diesem Grund bietet die Methode Find auch die Option an, als zweiten Parameter die Anzahl der zu überspringenden Datensätze zu übergeben, so dass die erneute Suche erst nach dieser Datensatzposition gestartet wird. Wenn zum Beispiel alle Kunden aus der Stadt London ermittelt werden sollen, könnte die Suche über die Methode Find zum Beispiel so aussehen. Über den Aufruf der TADODataSet-Methode <b>Resync</b> sorge ich dafür, dass die von der Recordset-Methode Find gefundenen Datensätze auch im TDBGrid als aktuelle Datensätze dargestellt werden (hinter <i>FRSFind</i> verbirgt sich ein privates Objektfeld des Formulars vom Typ <i>_Recordset</i>).
                <pre>
                procedure TForm1.ButtonFindClick(Sender: TObject);
                begin
                FRSFind := ADODataSet1.Recordset;
                FRSFind.Find(Format('City = %s', [QuotedStr(EditLocate.Text)]),
                0, adSearchForward, EmptyParam);
                ADODataSet1.Resync([rmExact]);
                end;

                procedure TForm1.ButtonFindNextClick(Sender: TObject);
                begin
                FRSFind.Find(Format('City = %s', [QuotedStr(EditLocate.Text)]),
                1, adSearchForward, EmptyParam);
                if FRSFind.EOF then begin
                ShowMessage('Keine weiteren Fundstellen');
                FRSFind.MoveFirst;
                end;
                ADODataSet1.Resync([rmExact]);
                end;
                </pre>
                Wird beim nächsten Aufruf von Find als zweiter Parameter der Wert 1 übergeben, so überspringt ADO den aktuellen Datensatz (also die letzte Fundstelle), so dass die Methode Find die nächste Fundstelle positioniert ( = Ersatz für die fehlende Methode FindNext).

                &gt;ganz verstehe ich das noch nicht, wir verwenden eigentlich einen ctKeyset Cursor

                Da Haken liegt beim fehlenden Locktype <b>ltReadOnly</b>. Nur dann, wenn es sich um eine Read-Only-Datenmenge handelt (bei der keine Update-Zugriffe über eine Transaktion möglich sind), darf ADO ungestraft im Hintergrund automatisch eine neue Verbindung (Connection) zur Datenbank aufbauen. Da die Datenmenge aber editierbar sein soll, ist dies nicht erlaubt (um kein Transaktions-Chaos zu provozieren).

                &gt;Auf alle Fälle kommt clUseClient aus verschiedenen Gründen im Moment leider nicht in Frage.

                In diesem Fall muss man selbst mehrere TADOConnections vorsehen und die Datenmengen (TADODataSets) voneinander abschotten, indem diese verschiedenen Verbindungen zugeordnet werden.

                P.S: Es ist wie beim Telefon: Wenn ein Familienmitglied als "Quasselstrippe" stundenlang mit der besten Freundin telefoniert, muss man a) entweder warten oder b) zu IDSN greifen - weil man dort ne 2. Nummer + Leitung hat :-

                Comment

                Working...
                X