Delphiを例として使用してCachéDBMSオブジェクトを操作する



Delphiの恒久的な葬儀にもかかわらず、デスクトップアプリケーションを構築するためのこのプラットフォームは健在であり、所有権の変更に伴い、2番目の風が吹いて、世界中の何千人もの開発者にとって主要なツールであり続けています。

他のDBMSと同様に、DelphiはCachéDBMSとうまくやり取りします。



Delphiから、以下のインターフェイスを使用してCachéに接続できます。





この記事では、CachéDBMSを操作するときにオブジェクト・インターフェースを使用する例を説明します。





しかし、最初に、Windows Explorerから直接実行できるVBScriptの短い例をいくつか紹介します。



直接アクセスの例:
Set f = CreateObject("VISM.VisMCtrl.1") f.Server="CN_IPTCP:localhost[1972]:_system:@ SYS" f.NameSpace="SAMPLES" f.Execute("=$zv") '   WScript.Echo f.VALUE
      
      





リレーショナルアクセスの例:
 Set cn=Createobject("ADODB.Connection") cn.ConnectionString="DRIVER={InterSystems ODBC35}; SERVER=127.0.0.1; PORT=1972; DATABASE=SAMPLES; UID=_system; PWD=SYS" cn.open WScript.Echo "Succesfully!"
      
      





オブジェクトアクセスの例:
 Set f = CreateObject("CacheActiveX.Factory") Set rs = CreateObject("CacheActiveX.ResultSet") If Not f.IsConnected() Then f.Connect("cn_iptcp:127.0.0.1[1972]:SAMPLES:_SYSTEM:SYS") Set rs=f.DynamicSQL("select TOP 3 * from Sample.Person") rs.Execute() while rs.Next WScript.Echo rs.Get("SSN") '  SSN      Sample.Person wend rs.Close() Set person = f.Static("Sample.Person") age=person.CurrentAge(45678) '   Sample.Person WScript.Echo age End If
      
      





同様に、JScript、Visual Basic、C ++ Builderなどを使用してCachéDBMSを操作できます。

注:より多くの機能を提供するJavaおよび.NETのネイティブインターフェイスがいくつかあります。


後期および早期バインディング



DelphiのCachéオブジェクトを操作するには、2つのアプローチがあります。



これらのアプローチにはそれぞれ長所と短所がありますが、互いに相殺されます。



遅延バインディングでは、開発者がコードヒントを利用できないため、コードの間違いを犯す可能性が高く、プログラムの実行中にのみ検出されます。 コードは動的に実行されるため、操作の速度は事前バインディングよりもわずかに遅くなります。



アーリーバインディングにはこれらの欠点はありませんが、データベース内のユーザークラスインターフェイスを変更するときや、CachéDBMSの新しいバージョン切り替えるときは、クライアントアプリケーションのプロキシクラスを再生成する必要があるため、費用を支払う必要があります。



これらのアプローチの両方を組み合わせることにより、最適なパフォーマンスと使いやすさを実現できます。



このアプローチは遅延バインディングよりも説明されていないため、この記事では主に事前バインディングを使用します。



Cachéオブジェクトは、デフォルトでCにインストールされる2つのライブラリを使用して動作します。\ Program Files \ Common Files \ InterSystems \ Cache \



インターシステムズの開発者は、 Caché5.1以降 、新しいCacheActiveX.dllライブラリの使用を強くお勧めします。 CacheObject.dllライブラリ 、古いアプリケーションとの互換性のためにのみ残されています。 したがって、この記事ではCacheActiveX.dllに基づいて説明します。



これらのライブラリと、新しいバージョンにアップグレードするときに考慮する必要がある微妙な違いの違いについては、「CacheObject.dllからのアップグレード」を参照してください



上記のディレクトリで、あなたに役立つ他のファイルを見つけることができます:



DelphiでCachéオブジェクトActiveXコンポーネントをインポートおよびインストールします



このセクションでは、事前バインディングを使用してCachéDBMSのオブジェクトを操作するために、Delphi環境で基本的なクラスとインターフェイスを設定する方法について説明します。 遅延バインディングを使用するには、このセクションをスキップできます。



だから、順番に:

  1. メニュー項目[ コンポーネント ] > [コンポーネントのインポート... ]を選択します。



    画像



    画像



  2. まず、 CacheActiveX 2.0タイプライブラリを選択します。



    画像



  3. コンポーネントをインストールするブックマークの名前と他のパラメーターを設定します。



    画像



  4. これまで、インストールせずにモジュールを作成しました。



    画像



  5. 次のライブラリについて手順2〜4を繰り返します。

    • CacheActiveX 2.0タイプライブラリ ;
    • CacheList ActiveXコントロールモジュール
    • CacheQuery ActiveX Controlモジュール
    • DelphiCallback 1.0タイプライブラリ
    • VisM 7.2 ActiveXコントロール
    • TL 1.0タイプライブラリ
    注:Delphiに含まれているtlibimp.exeユーティリティを使用してモジュールを作成することもできます。


  6. パッケージタイプの新しいプロジェクトを作成し、以前に作成したすべてのモジュールを追加します。 プロジェクトをコンパイルし、パッケージをインストールします。 最終的には次のようになります。



    画像



    画像

    注:Delphiの以前のバージョンでは、モジュールを作成するプロセスが少し異なります。

    • メニュー項目[ プロジェクト ] > [タイプライブラリのインポート... ]を選択します。



      画像



    • 上記の段落を参照してください。


カスタムプロキシクラスの生成



このセクションでは、事前バインディングを使用してCachéDBMSのオブジェクトを操作するためのカスタムプロキシクラスの生成について説明します。 遅延バインディングを使用するには、このセクションをスキップできます。



まず、必要なすべてのユーザークラスを含むODLファイルを生成する必要があります。 これを行うには、 CachéDBMSで提供されるodl_generator.exeユーティリティを使用します。



 odl_generator.exe -conn cn_iptcp:localhost[1972]:USER:_system:SYS -class-list test.txt -lib-name test -dir MIDL
      
      





この例では、ユーティリティはUSER領域に接続し、 test.txtファイルにリストされているクラスのプロキシクラスを生成し、結果をMIDL \ test.odlファイルに保存します

:このようにして取得されたファイルは、 CacheActiveX.dllライブラリで使用するためのものです。 古いライブラリで動作するように設計されたODLファイルを生成するには、 %SYSTEM.OBJクラスのExportODLメソッドを使用します





set list= "%Library.Status,Sample.Person"

do $system .OBJ . ExportODL (list, "c:\MIDL\test.odl" , "-d" ,.err)







ODLファイルが受信されたので、TLBファイルを取得するためにコンパイルし、次にPASファイルを取得する必要があります。 これを行うには、Visual C ++開発キットに含まれているmidl.exeまたはmktypelib.exeユーティリティを使用できます。



 midl /I . test.odl /tlb test.tlb tlibimp.exe -C- -P+ -Hr- -Ha- -Hs- -XM- test.tlb
      
      





Note:CachéDBMS MACプログラムを使用して、上記のすべてのステップを自動化できます。


サーバーでの準備作業



テストデータベースに次のデータクラスを作成しましょう。



///

Class pas.s Extends %SerialObject

{



/// (64-).

Property
aInteger As %Integer ;



/// . - 50 .

Property
aString As %String ;



}






/// .

Class pas.a Extends %Persistent

{



/// aA;

Index
aAIndex On aA;



/// --, "". SQL foreign key.

Relationship
aA As pas.test [ Cardinality = one, Inverse = aChilds ];



Property aInteger As %Integer ;



Property aString As %String ;



}






/// %occIO.inc .

Include
%occIO



/// .

Class pas.test Extends %Persistent

{



/// , ;

Parameter
EXTENTQUERYSPEC As ROWSPEC [ Flags = LIST ] = aBoolean,aInteger,aString,aDate,aTimeStamp" ;



/// (true/false/null);

Property
aBoolean As %Boolean ;



Property aInteger As %Integer ;



Property aString As %String ;



/// ;

Property
aDate As %Date ;



/// +;

Property
aTimeStamp As %TimeStamp ;



/// (CLOB);

Property
aMemo As %GlobalCharacterStream ;



/// (BLOB);

Property
aPhoto As %GlobalBinaryStream ;



/// --, "". SQL .

Relationship
aChilds As pas.a [ Cardinality = many, Inverse = aA ];



/// - ;

///<br> SQL

///<br> -.

Property
aS As pas.s ;



/// - ;

///<br> SQL , , .

Property
aListOfString As list Of %String ;



/// - ;

///<br> SQL , , .

Property
aListOfA As list Of pas.a ;



/// - ;

///<br> SQL .

Property
aArrOfString As array Of %String ;



/// - ;

///<br> SQL .

Property
aArrOfA As array Of pas.a ;



/// .

/// <br> , .

Method
%OnBeforeSave( insert As %Boolean ) As %Status [ Private , ServerOnly = 1 ]

{

;

write "Hello from Cache! (" , $$$CurrentClass , ":" , $$$CurrentMethod , ")" ,!



quit $$$OK

}



/// - : .

Query
test1( ABoolean As %Boolean , AInteger As %Integer , AString As %String , ADate As %Date , ATimeStamp As %TimeStamp ) As %SQLQuery ( CONTAINID = 1 , ROWSPEC = "ID:%String,aBoolean:%Boolean,aInteger:%Integer,aString:%String,aDate:%Date,aTimeStamp:%TimeStamp" ) [ SqlProc ]

{

SELECT %ID , aBoolean , aInteger , aString , aDate , aTimeStamp FROM pas . test WHERE

( aBoolean = :ABoolean or :ABoolean is null )

AND (
aInteger = :AInteger or :AInteger is null )

AND (
aString = :AString or :AString is null )

AND (
aDate < :ADate or :ADate is null )

AND (
aTimeStamp <= :ATimeStamp or :ATimeStamp is null )

}



/// - : ""

///<br> %INLIST.

Query
test2( AList As %List ) As %SQLQuery ( CONTAINID = 1 , ROWSPEC = "ID:%String,aBoolean:%Boolean,aInteger:%Integer,aString:%String,aDate:%Date,aTimeStamp:%TimeStamp" ) [ SqlProc ]

{

SELECT %ID , aBoolean , aInteger , aString , aDate , aTimeStamp FROM pas . test WHERE ID %INLIST :AList

}



/// .

ClassMethod
test3( AList As %List ) As %Status

{

; AList

write AList



;

set ^pastest=AList



quit $$$OK

}



/// .

ClassMethod
test4() As %Status

{

quit $$$ERROR ( $$$GeneralError , "My error!" )

}



/// .

ClassMethod
test5( Arg1... As %List ) As %Status

{

;

write "Invocation has " , $get (Arg1, 0), " element" , $select (( $get (Arg1, 0)=1): "" , 1: "s" ),!

for i = 1 : 1 : $get (Arg1, 0)

{

write :( $data (Arg1(i))>0) "Argument[" ,i, "]:" ,?15, $get (Arg1(i), "<NULL>" ),!

}

quit $$$OK

}



/// : .

/// <br> .

/// <br>:

/// <br><var>ID</var> - ;

/// <br><var>A</var> - ;

/// <br><var>BLOB</var> - ;

/// <br><var>RS1</var> - , Borland ® MyBase (DataSnap (TM)) XML DataSet;

/// <br><var>RS2</var> - , Borland ® MyBase (DataSnap (TM)) XML DataSet;

ClassMethod
test6(

ID As %String ,

ByRef A As pas.a ,

Output BLOB As %BinaryStream ,

Output RS1 As %CharacterStream ,

Output RS2 As %CharacterStream ) As %Status

{

// ,

set A. aString =999



//

set BLOB= ##class ( %GlobalBinaryStream ). %New ()



//

do BLOB. Write ( "123" )



//

set RS1= ##class ( %GlobalCharacterStream ). %New ()

set RS2= ##class ( %GlobalCharacterStream ). %New ()



// , XML TClientDataSet

set cds= ##class ( %XML.ZMyBaseDataSet ). %New ()



//

do cds. Prepare ( "select * from pas.a where id %inlist ?" )



//

do cds. SetArgs ( $listbuild (1,2,3,9))



// XML

do cds. XMLExportToStream (.RS1)



// ( )

do cds. Close ()

do cds. Prepare ( "select ID,aBoolean,aInteger,aString,aDate,aTimeStamp from pas.test" )

do cds. XMLExportToStream (.RS2)

do cds. Close ()



// ""

quit $$$OK

}



}






これらのプロキシクラスと、次のクラスのプロキシクラスを生成します。



生成されたPASファイルをプロジェクトに接続すると、クラスの最も重要なメソッドとプロパティが利用可能になります。



画像

増す



Note :ストリームクラスおよびその他のクラスは、CachéDBMSからインポートしないでください 。これらはすでにCacheActiveX.dllライブラリに接続されており、生成されたプロキシクラスと互換性がありません。


DBMSCachéへの接続



遅延バインディング(古いライブラリ):

 var _f:variant; begin _f:=CreateOleObject('CacheObject.Factory'); if _f.Connect(_f.ConnectDlg('+%up')) then ShowMessage('OK') else ShowMessage('ERROR');
      
      





遅延バインディング(新しいライブラリ):

 var _f:variant; begin _f:=CreateOleObject('CacheActiveX.Factory'); if _f.Connect(_f.ConnectDlg('+%up')) then ShowMessage('OK') else ShowMessage('ERROR');
      
      





事前バインディング(新しいライブラリ):

 type Tfm = class(TForm) f: TFactory; ... begin ... if f.Connect1(f.ConnectDlg('+%up')) then ShowMessage('OK') else ShowMessage('ERROR'); ...
      
      





:古いライブラリは%Service_CacheDirectサービスと認証されていないアクセスのみを使用し 、新しいライブラリは%Service_Bindingsおよびその他のアクセス方法を使用します。


TFactobryクラスおよび他のクラスのメソッドの詳細な説明は、 ActiveX APIリファレンスにあります。



アーリーバインディングを使用してクエリとメソッドを呼び出す例



コールバック機能を使用する


DelphiのCallBack機能を使用するには、 DelphiCallback.dllファイルの既製のTCallbackクラスを使用する必要があります。

 var f:TFactory; Callback1: TCallback; mm: TMemo; ... f.SetOutput(Callback1.OleObject); ... procedure Tfm.Callback1TextChanged(Sender: TObject; const p_bstrText: WideString); begin mm.Lines.Append(p_bstrText); end;
      
      





すべてのデータを削除する


  mm.Lines.Text:='KillExtent'#10#13; //   test_(f.Static('pas.test')).SYS_KillExtent(1); a(f.Static('pas.a')).SYS_KillExtent(1);
      
      





さまざまなタイプのオブジェクトの作成、入力、保存、および解放の例


Sergey Kudinovの記事「ActiveXで作業するときのオブジェクトを閉じる機能、CPP-binding」で記事を読むことができます。



コード例:

 ... uses test_TLB, AxCtrls, ComObj, ActiveX, Types; ... const N = 3; var i: integer; _t: test_; _a: A; _s: s; rel: RelationshipObject; listStr: ListOfDataTypes; listA: ListOfObjects; arrStr: ArrayOfDataTypes; arrA: ArrayOfObjects; stream: IDispatch; begin Screen.Cursor := crSQLWait; mm.Lines.Text:='Save'#10#13; try try //     pas.test _t := test_(f.New('pas.test')); //     _t.aBoolean := true; _t.aInteger := 50; _t.aString := ' '; //     null    // (%Integer,%Boolean,%Date  ..) Variant(_t).aDate := nil; _t.aDate := _t.aDateDisplayToLogical('02.03.2001'); //  t.aDate:=StrToDate('02.03.2001'); _t.aTimeStamp := _t.aTimeStampDisplayToLogical('1900-01-02 12:34:55'); //  t.aTimeStamp:=StrToDateTime('02.01.1900 12:34:55'); //     stream := _t.aMemo; ICharStream(stream).Write(' '); stream := nil; //     stream := _t.aPhoto; IBinaryStream(stream).FileRead('C:\test.jpg'); stream := nil; //  N ""   pas.a rel := RelationshipObject(_t.aChilds); for i := 1 to N do begin _a := A(f.New('pas.a')); _a.aInteger := i; _a.aString := 'rel' + IntToStr(i); rel.Insert(_a); _a.SYS_Close; end; _t.aChilds := rel; rel.SYS_Close; //     _s := s(_t.aS_); _s.aInteger := 1; _s.aString := 's1'; _s.SYS_Close; //     .     listStr := ListOfDataTypes(f.New('%ListOfDataTypes')); for i := 1 to N do listStr.Insert('str' + IntToStr(i)); _t.aListOfString := listStr; listStr.SYS_Close; //    pas.a     listA := ListOfObjects(f.New('%ListOfObjects')); for i := 1 to N do begin _a := A(f.New('pas.a')); _a.aInteger := i; _a.aString := 'listA' + IntToStr(i); listA.Insert(_a); _a.SYS_Close; end; _t.aListOfA := listA; listA.SYS_Close; //     .     arrStr := ArrayOfDataTypes(f.New('%ArrayOfDataTypes')); for i := 1 to N do arrStr.SetAt('astr' + IntToStr(i), 'arraykey' + IntToStr(i)); _t.aArrOfString := arrStr; arrStr.SYS_Close; //    pas.a     arrA := ArrayOfObjects(f.New('%ArrayOfObjects')); for i := 1 to N do begin _a := A(f.New('pas.a')); _a.aInteger := i; _a.aString := 'arrayA' + IntToStr(i); arrA.SetAt(_a, 'arraykey' + IntToStr(i)); _a.SYS_Close; end; _t.aArrOfA := arrA; arrA.SYS_Close; //         .   //          // . _t.SYS_Save(0); //          stream := _t.aPhoto; SetOlePicture(img.Picture, IBinaryStream(stream).GetPicture); stream := nil; //    .      //   ,  "" (%sysOrefs). //         //       . _t.SYS_Close; //     _t := nil; mm.Lines.Append('OK'); except on E: Exception do begin mm.Lines.Append(E.Message); end; end; finally Screen.Cursor := crDefault; //      , //      f.ForceSync; end;
      
      





エクステントリクエスト(保存されたクラスのすべてのインスタンスを取得)


 var mm: TMemo; rs: TResultSet; ... mm.Lines.Text:='Extent'#10#13; rs.ConnectTo(IResultSet(f.ResultSet('pas.test', 'Extent'))); rs.Execute; while rs.Next do begin mm.Lines.Append(Format('ID = %s',[rs.GetDataAsString(1)])); mm.Lines.Append(Format('aBoolean = %s',[rs.Get('aBoolean')])); mm.Lines.Append(Format('aInteger = %s',[rs.Get('aInteger')])); mm.Lines.Append(Format('aString = %s',[rs.Get('aString')])); mm.Lines.Append(Format('aDate = %s',[rs.Get('aDate')])); mm.Lines.Append(Format('aTimeStamp = %s',[rs.Get('aTimeStamp')])); mm.Lines.Append('-----'); end; rs.Close; rs.Disconnect;
      
      





クエリtest1


 var i: integer; ... mm.Lines.Text:='test1'#10#13; rs.ConnectTo(IResultSet(f.ResultSet('pas.test', 'test1'))); rs.SetParam(1, null); rs.SetParam(2, 50); rs.SetParam(3, null); rs.SetParam(4, '03.03.2001'); rs.SetParam(5, '1900-01-02 12:34:55.0'); rs.Execute; while rs.Next do begin for i := 1 to rs.GetColumnCount do mm.Lines.Append(rs.GetColumnName(i)+' = '+rs.GetDataAsString(i)); mm.Lines.Append('-----'); end; rs.Close; rs.Disconnect;
      
      





クエリtest2


 var i: integer; syslist: TSyslist; ... mm.Lines.Text:='test2'#10#13; //    %List syslist.Clear; syslist.Add(1); syslist.Add(2); syslist.Add(3); rs.ConnectTo(IResultSet(f.ResultSet('pas.test', 'test2'))); rs.Execute(syslist.DefaultInterface); while rs.Next do begin for i := 1 to rs.GetColumnCount do mm.Lines.Append(rs.GetColumnName(i)+' = '+rs.GetDataAsString(i)); mm.Lines.Append('-----'); end; rs.Close; rs.Disconnect;
      
      





メソッドtest3。 クラスTSysList(Cachéのtype%List)のオブジェクトの操作


  mm.Lines.Text:='test3'#10#13; //    %List syslist.Clear; syslist.Add('16'); syslist.Add('42'); syslist.Add('35'); test_(f.Static('pas.test')).test3(syslist.DefaultInterface);
      
      





メソッドtest4。 エラー処理


  mm.Lines.Text:='test4'#10#13; try test_(f.Static('pas.test')).test4(); except on E: Exception do begin mm.Lines.Append(E.Message); end; end;
      
      





Test5メソッド


  mm.Lines.Text:='test5'#10#13; //    %List syslist.Clear; syslist.Add('16'); syslist.Add('42'); syslist.Add('35'); test_(f.Static('pas.test')).test5(syslist.DefaultInterface);
      
      





Test6メソッド


この例では、 %XML.ZMyBaseDataSetクラスを使用します 。これは、 こちらにあります 。 その助けにより、サーバー上でBorland®MyBase(DataSnap(TM))XML DataSetの形式でデータを形成することができます。 Webサービスを含む。



 cds1,cds2:TClientDataSet; ... var _a:a; __a,blob,rs1,rs2:IDispatch; cs1,cs2:ICharStream; begin mm.Lines.Text:='test6'#10#13; try _a:=a(f.OpenId('pas.a','1')); __a:=_a; test_(f.Static('pas.test')).test6('1',__a,blob,rs1,rs2); cs1:=ICharStream(rs1); cs2:=ICharStream(rs2); mm.Lines.Append('A.aString = '+_a.aString); mm.Lines.Append('BLOB.Size = '+IntToStr(IBinaryStream(blob).size)); mm.Lines.Append('RS1.Size = '+IntToStr(cs1.size)); mm.Lines.Append('RS2.Size = '+IntToStr(cs2.size)); cds1.XMLData:=cs1.Data; cds2.XMLData:=cs2.Data; finally _a.SYS_Close; _a:=nil; __a:=nil; blob:=nil; rs1:=nil; rs2:=nil; cs1:=nil; cs2:=nil; f.ForceSync; end;
      
      





Unicodeのデータの%XML.ZMyBaseDataSetクラスおよびその他の未実現データ型をサポートするには、自分で変更する必要があります。



アプリケーション配布


アプリケーションで必要なすべてのドライバーを新しいコンピューターにインストールするには、 C:\ Program Files \ Common Files \ InterSystems \ Cache \ディレクトリからすべてのファイル(簡単にするために必要なファイルのセットを制限できます)をコピーし、 regsvr32ユーティリティを使用してそれらの一部をシステムに登録する必要があります.exe





 regsvr32.exe /s "C:\Program Files (x86)\Common Files\Intersystems\Cache\CacheQuery.ocx" regsvr32.exe /s "C:\Program Files (x86)\Common Files\Intersystems\Cache\CacheFormWizard.dll" regsvr32.exe /s "C:\Program Files (x86)\Common Files\Intersystems\Cache\CacheList.ocx" regsvr32.exe /s "C:\Program Files (x86)\Common Files\Intersystems\Cache\CacheActiveX.dll" regsvr32.exe /s "C:\Program Files (x86)\Common Files\Intersystems\Cache\vism.ocx" regsvr32.exe /s "C:\Program Files (x86)\Common Files\Intersystems\Cache\TL.dll"
      
      





ソースコード





All Articles