Announcement

Collapse
No announcement yet.

Three Tier Applikation

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

  • Three Tier Applikation

    <b> Hallo erst mal. </b>

    Ich möchte eine mehrschichtige Datenbankanwendung erstellen, die in der zweiten Schicht die Daten aus einem MS SQL Server liest und diese in Memtables bereitstellt und deren Integrität überprüft.

    Ich habe dieses mit einem COM+ Server versucht. Dieser ruft für jeden Klienten wieder die gesamten Daten ab und somit können die Daten untereinander nicht berücksichtigt werden.

    Ich benötige einen Server der nach dem ersten Aufruf resistent bleibt und somit für beide Klienten die selben Daten im Hauptspeicher vorhält.

    <b> Grüße

    Hendrik</b>

  • #2
    Hallo,

    &gt;..für beide Klienten die selben Daten im Hauptspeicher vorhält.

    Da bei COM+ der Kontext immer im Spiel ist, kann es rein technisch betrachtet keinen <i>Singleton</i>-Server geben, bei dem alle Base-Clients mit der exakt gleichen Objektinstanz arbeiten.

    Allerdings darf jedes dieser separaten COM+ Objekte ein gemeinsam genutztes drittes COM+ Objekt aufrufen, das in einem Objekt-Pool mit der minimalen und maximalen Poolgröße von 1 ausgeführt wird. Dieses gepoolte COM+ Objekt stellt dann für alle anderen kurzzeitig aktiven (JITA) COM+ Objektinstanzen die Datenmenge bereit - wobei aber aufgrund der maximalen Poolgröße von 1 alle Aufrufe durch die anderen COM+ Objekte serialisiert werden. Die COM+ Anwendung ist somit nur eingeschränkt skalierbar

    Comment


    • #3
      Dankeschön Herr Kosch für Ihre schnelle Antwort.

      Könnten Sie mir vielleicht kurz erläutern, wie ich dieses dritte COM+ Objekt so einstellen und erzeugen kann, das es sich wie gewünscht verhält ?

      Vielen Dank in voraus
      Hendri

      Comment


      • #4
        Hallo,

        &gt;...wie ich dieses dritte COM+ Objekt so einstellen und erzeugen kann...

        Das zu poolende COM+ Objekt meldet sich als <b>TNA</b> (Thread-Neutral-Apartment) an und überschreibt auch die IObjectControl-Interfacemethode <b>CanBePooled</b>:
        <pre>
        <b>unit</b> ObjPool_Impl;
        <br>
        <b>interface</b>
        <br>
        <b>uses</b>
        Windows, ActiveX, MtsObj, Mtx, ComObj, ObjPool_TLB, StdVcl;
        <br>
        <b>type</b>
        TObjectPool = <b>class</b>(TMtsAutoObject, IObjectPool)
        <b>private</b>
        FValue : Integer;
        <b>protected</b>
        <b>function</b> Get_Version: Integer; <b>safecall</b>;
        <b>function</b> DoWork(cNetto: Currency; out sMsg: WideString): Currency;
        <b>safecall</b>;
        <font color="#003399"><i>{ Protected-Deklarationen }</i></font>
        <b>function</b> CanBePooled: Bool; <b>stdcall</b>;
        <b>end</b>;
        <br>
        <b>var</b>
        gValue : Integer;
        <br>
        <b>implementation</b>
        <br>
        <b>uses</b> SysUtils, ComServ;
        <br>
        <b>type</b>
        TTNAAutoObjectFactory = <b>class</b>(TAutoObjectFactory)
        <b>procedure</b> UpdateRegistry(<b>Register</b>: Boolean); <b>override</b>;
        <b>end</b>;
        <br>
        <font color="#003399"><i>{ TTNAAutoObjectFactory }</i></font>
        <br>
        <b>procedure</b> TTNAAutoObjectFactory.UpdateRegistry(<b>Register</b>: Boolean);
        <b>var</b>
        sClassID, sServerKeyName: <b>String</b>;
        <b>begin</b>
        <b>inherited</b> UpdateRegistry(<b>Register</b>);
        <b>if</b> <b>Register</b> <b>then</b>
        <b>begin</b>
        <b>if</b> Instancing = ciInternal <b>then</b> Exit;
        sClassID := GUIDToString(ClassID);
        sServerKeyName := <font color="#9933CC">'CLSID\'</font> + sClassID + <font color="#9933CC">'\'</font> + ComServer.ServerKey;
        <b>if</b> (ThreadingModel &lt;&gt; tmSingle) <b>and</b> IsLibrary <b>then</b>
        CreateRegKey(sServerKeyName, <font color="#9933CC">'ThreadingModel'</font>, <font color="#9933CC">'Neutral'</font>);
        <b>end</b>;
        <b>end</b>;
        <br>
        <font color="#003399"><i>{ IObjectControl }</i></font>
        <br>
        <b>function</b> TObjectPool.CanBePooled: Bool;
        <b>begin</b>
        Result := True;
        <b>end</b>;
        <br>
        <font color="#003399"><i>{ IObjectPool-Interface des eigenen COM+ Objekts }</i></font>
        <br>
        <b>function</b> TObjectPool.Get_Version: Integer;
        <b>begin</b>
        Result := 1;
        SetComplete;
        <b>end</b>;
        <br>
        <b>function</b> TObjectPool.DoWork(cNetto: Currency;
        out sMsg: WideString): Currency;
        <b>begin</b>
        Inc(FValue);
        InterlockedIncrement(gValue);
        Result := cNetto * 1.16;
        sMsg := Format(<font color="#9933CC">'FValue: %d; gValue: %d; Thread: %d'</font>,
        [FValue, gValue, GetCurrentThreadID]);
        SetComplete;
        <b>end</b>;
        <br>
        <b>initialization</b>
        TTNAAutoObjectFactory.Create(ComServer, TObjectPool, Class_ObjectPool,
        ciMultiInstance, tmApartment);
        </pre>
        Im Eigenschaftsdialog des COM+ Objekts wird dann nach der Installation der DLL in der COM+ Anwendung für das COM+ Objekt die Eigenschaft <b>Objektpooling aktivieren</b> eingeschaltet (Checkbox ankreuzen), wobei die minimale und maximale Poolgröße über die beiden Eingabelder auf 1 Objekt festgesetzt wird

        Comment


        • #5
          Hallo Herr Kosch,

          ich habe einen Server erstellt und Ihre Angaben
          berücksichtigt, aber ich kann einfach das Pooling nicht aktivieren. Die Checkbox bleibt inactive.

          Ich habe es so gemacht, wie Sie es hier <A Href:"<a href="/webx?50@@.ee8e05e">Schlubberblubb "Beispiele aus dem Buch Com/Dcom COM+" 12.02.2003 11:42</a>">hier</a> beschreiben.

          Haben Sie vielleicht eine Idee was ich falsch mache ?

          Grüße

          Hendrik

          <pre>
          unit LDBSERVER_UNIT;

          interface

          uses
          Windows,ComObj, ActiveX, LDB_TLB, StdVcl, COMSVCSLib_TLB, ADODB_TLB,ADODB;

          type
          TLDBSERVER = class(TAutoObject, IObjectControl, ILDBSERVER)
          private
          FObjectContext: IObjectContext;
          protected
          // IObjectControl-Methoden aus COMSVCSLib_TLB kopieren
          function Activate: HResult; stdcall;
          procedure Deactivate; stdcall;
          function CanBePooled: Integer; stdcall;
          function Get_Daten: OleVariant; safecall;
          procedure Set_Daten(Daten: OleVariant); safecall;
          end;

          implementation

          uses ComServ,LDBDATEN_SERVER;

          function CoGetObjectContext(const iid: TIID;
          ppv: Pointer): HResult; stdcall;
          external 'ole32.dll' name 'CoGetObjectContext';

          function TLDBSERVER.Activate: HResult;
          begin
          try
          OleCheck(CoGetObjectContext(IID_IObjectContext , @FObjectContext));
          Result := S_OK;
          except
          Result := E_NOTIMPL;
          end;
          end;

          function TLDBSERVER.CanBePooled: Integer;
          begin
          Result := Integer(TRUE);
          end;

          procedure TLDBSERVER.Deactivate;
          begin
          FObjectContext := nil;
          end;

          function TLDBSERVER.Get_Daten: OleVariant;
          var adoRS1: ADODB_TLB._Recordset;
          begin
          adoRS1 := CoRecordset.Create;
          adoRS1 := IDispatch(Data.Table1.Recordset) as AdoDB_TLB._Recordset;
          Result := adoRS1;
          end;

          procedure TLDBSERVER.Set_Daten(Daten: OleVariant);
          var i,j:Integer;
          begin
          DATA.TEMP.Recordset := IDispatch(DATEN) as AdoDB._Recordset;
          While not DATA.TEMP.EOF do
          begin
          If DATA.TEMP.RecordStatus = [rsModified] then
          begin
          DATA.TABLE1.Filtered := False;
          DATA.TABLE1.Filter := 'ID = ' + DATA.Temp.FieldByName('ID').AsString;
          DATA.TABLE1.Filtered := True;

          IF DATA.TABLE1.FieldByName('ID').asInteger = DATA.Temp.FieldByName('ID').asInteger then
          begin
          For i := 0 to DATA.TEMP.Fields.Count - 1 do
          begin
          DATA.TABLE1.Edit;
          If (DATA.TEMP.Fields[i].FullName <> 'ID') AND (DATA.TEMP.Fields[i].FullName <> 'UPDDATE') AND (DATA.TEMP.Fields[i].FullName <> 'INSDATE') then
          begin
          DATA.TABLE1.Fields[i].Value := DATA.TEMP.Fields[i].Value;
          end;
          DATA.TABLE1.Post;
          end;
          end;
          end;
          DATA.TEMP.Next;
          end;
          end;

          initialization
          TAutoObjectFactory.Create(ComServer, TLDBSERVER, Class_LDBSERVER,
          ciMultiInstance, tmApartment);
          end.
          </pre&gt

          Comment


          • #6
            Hallo,

            &gt;Haben Sie vielleicht eine Idee was ich falsch mache ?

            Ja - denn die folgende Anweisung meldet für das COM-Objekt über <b>tmApartment</b> ein <B>STA</b> (Single-threaded Apartment), und diese Dinger können nicht gepoolt werden:
            <pre>
            TAutoObjectFactory.Create(ComServer, TLDBSERVER, Class_LDBSERVER,
            ciMultiInstance, tmApartment);
            </pre>
            Erst dann, wenn ein MTA oder noch besser ein TNA aktiviert wird (siehe mein Beispiel), gibt der Eigenschaftsdialog die Pooling-Optionen frei

            Comment

            Working...
            X