2012-06-27コメント
元の投稿にはいくつかの便利なコードがありますが、クライアントアプリからの1回のリクエストでDataSnapサーバーから複数のデータセットを返す方法を実際には示していません。その方法の例を見るには、ページの一番下にある「正解」とマークされた回答を見てください。
2011-08-31コメント
ガニーのおかげで、私はすべてをもう一度見ました。厄介な問題は私自身のバグでしたが、現在は修正されています。各データベースクエリの間にコンポーネントを作成/破棄することで、単一のクライアントからサーバーへの要求内のDataSnapサーバーで複数のSQLステートメントを実行できます。TSQLQuery
(output
http://qc.embarcadero.com/wc/qcmain.aspx ? _ d = 90211)。TSQLStoredProc.Open
したがって、私の問題は解決されましたが、元の問題は残っています。メソッドを呼び出してOpen
データをプルしてからoutput
パラメータにアクセスすることはできません。また、単一のストアドプロシージャから返された複数のデータセットにアクセスすることもできません。
ガニー、あなたの提案にもう一度感謝します。
元の投稿
1回のリクエストでDataSnapサーバーから2つの異なるデータセットを返そうとしています。どちらも同じデータベースからのものです。1つは単一フィールド/単一レコード値であり、もう1つはマルチフィールド/マルチレコードデータセットです。
DataSnapサーバーには次の方法があります。
function TDSSvrMethods.GetData(const SQL: string; var Params: OleVariant; var Key: string): OleVariant;
var qry: TSQLQuery; cds: TClientDataSet;
begin
// create TSQLQuery & TClientDataSet
// Link the two components via cds.SetProvider(qry);
// run first query, set 'Key' to the result <-- this works
qry.Close;
// run second query <-- I see this hit the database
// return dataset via 'Result := cds.Data;'
// destory TSQLQuery & TClientDataSet
end;
これは機能しません。両方の個別のリクエストがデータベースにヒットしていることはわかりますが、2番目の結果セットにアクセスできません。試してみると、2番目の結果セットではなく最初の結果セットが(再び)返されます。
クエリコンポーネントを作成/破棄する前に(各クライアントからサーバーへのリクエストで)、後続のすべてのクライアントからサーバーへのリクエストは最初のデータセットを返していました。非常にイライラします。クエリコンポーネントを作成/破棄するとその問題は修正されましたが、1つのクライアントからサーバーへのリクエストで複数のクエリを実行すると、問題が返されます。新しいクエリが実行された場合でも、最初のデータセットが返されます。
私はいくつかのアプローチを試しました:
ONETSQLQuery
:最初のリクエストのコンポーネントを動的に作成し、db値をプルし、を破棄しTSQLQuery
、新しいデータセットを作成してTSQLQuery
、2番目のデータセットをプルします。それは役に立ちませんでした。SQL Server Profilerを使用して、両方のコマンドがデータベースにヒットすることを確認できますが、最初の結果セットが両方のクエリのデータセットとして表示されます。
TWO:#1と同じことを行いますが、TSQLStoredProcedure
の代わりに使用しTSQLQuery
ます。結果は同じです。
3:を使用してTSQLStoredProcedure
、次のように同じストアドプロシージャ内から両方のデータセットを返します。
create procedure sp_test_two_datasets
as
select 'dataset1' as [firstdataset]
select * from sometable -- 2nd dataset
go
TSQLStoredProcedure
を持っているのでNextRecordSet
、私は両方のデータセットにアクセスすることを望んでいましたが、喜びはありませんでした。を呼び出すとNextRecordSet
、が返されますnil
。
4TSQLStoredProcedure
:データセットとoutput
パラメーターを使用する1回の呼び出しで2つの値を返します。
create procedure sp_another_test
@singlevalue varchar(255) output
as
select * from sometable
go
Delphiのコードは次のようになります。
var sp: TSQLStoredProc; cds: TClientDataSet;
...
cds.SetProvider(sp);
...
sp.CommandText := 'sp_another_test :value output';
sp.Params.ParamByName('value').Value := Key; // in/out method parameter from above
sp.Open;
Key := sp.Params.ParamByName('value').Value; // single string value
Result := cds.Data; // dataset
...
sp.Paramsを調べたところ、。という名前のin/outパラメーターが1つありますvalue
。output
データセットも返されるときにパラメータにアクセスできません。これは既知のバグです(長年にわたって):http://qc.embarcadero.com/wc/qcmain.aspx?d = 90211
結論:
DataSnapサーバーはTSQLConnection
接続しているすべてのクライアントとメインを共有しており、TSQLQuery
(またはTSQLStoredProc
)とTClientDataSet
コンポーネントはすべてリクエストごとに作成/解放されるため、前のデータセットを保持してTSQLQuery
、TSQLStoredProc
コンポーネントはTSQLConnection
コンポーネントです。(または)コンポーネントTSQLConnection.CloseDataSets
を閉じて解放する前に呼び出してみましたが、それも役に立ちませんでした。TSQLQuery
TStoredProc
おそらく、よく見るTSQLConnection
と役立つでしょう。.dfm
ファイル内での表示は次のとおりです。
object sqlcon: TSQLConnection
DriverName = 'MSSQL'
GetDriverFunc = 'getSQLDriverMSSQL'
LibraryName = 'dbxmss.dll'
LoginPrompt = False
Params.Strings = (
'SchemaOverride=%.dbo'
'DriverUnit=DBXMSSQL'
'DriverPackageLoader=TDBXDynalinkDriverLoader,DBXCommonDriver150.' +
'bpl'
'DriverAssemblyLoader=Borland.Data.TDBXDynalinkDriverLoader,Borla' +
'nd.Data.DbxCommonDriver,Version=15.0.0.0,Culture=neutral,PublicK' +
'eyToken=91d62ebb5b0d1b1b'
'MetaDataPackageLoader=TDBXMsSqlMetaDataCommandFactory,DbxMSSQLDr' +
'iver150.bpl'
'MetaDataAssemblyLoader=Borland.Data.TDBXMsSqlMetaDataCommandFact' +
'ory,Borland.Data.DbxMSSQLDriver,Version=15.0.0.0,Culture=neutral' +
',PublicKeyToken=91d62ebb5b0d1b1b'
'GetDriverFunc=getSQLDriverMSSQL'
'LibraryName=dbxmss.dll'
'VendorLib=sqlncli10.dll'
'HostName=localhost'
'Database=Database Name'
'MaxBlobSize=-1'
'LocaleCode=0000'
'IsolationLevel=ReadCommitted'
'OSAuthentication=False'
'PrepareSQL=True'
'User_Name=user'
'Password=password'
'BlobSize=-1'
'ErrorResourceFile='
'OS Authentication=False'
'Prepare SQL=False')
VendorLib = 'sqlncli10.dll'
Left = 352
Top = 120
end
また、実行時に、DBXドライバー用の.INIファイルを展開する必要がないようにいくつかのことを行います。まず、自分のINIレスドライバーを登録できるユニット:
unit DBXRegDB;
interface
implementation
uses
DBXCommon, DBXDynalinkNative;
type
TDBXInternalDriver = class(TDBXDynalinkDriverNative)
public
constructor Create(DriverDef: TDBXDriverDef); override;
end;
TDBXInternalProperties = class(TDBXProperties)
private
public
constructor Create(DBXContext: TDBXContext); override;
end;
{ TDBXInternalDriver }
constructor TDBXInternalDriver.Create(DriverDef: TDBXDriverDef);
begin
inherited Create(DriverDef, TDBXDynalinkDriverLoader);
InitDriverProperties(TDBXInternalProperties.Create(DriverDef.FDBXContext));
end;
{ TDBXInternalProperties }
constructor TDBXInternalProperties.Create(DBXContext: TDBXContext);
begin
inherited Create(DBXContext);
Values[TDBXPropertyNames.SchemaOverride] := '%.dbo';
Values[TDBXPropertyNames.DriverUnit] := 'DBXMSSQL';
Values[TDBXPropertyNames.DriverPackageLoader] := 'TDBXDynalinkDriverLoader,DBXCommonDriver150.bpl';
Values[TDBXPropertyNames.DriverAssemblyLoader] := 'Borland.Data.TDBXDynalinkDriverLoader,Borland.Data.DbxCommonDriver,Version=15.0.0.0,Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b';
Values[TDBXPropertyNames.MetaDataPackageLoader] := 'TDBXMsSqlMetaDataCommandFactory,DbxMSSQLDriver150.bpl';
Values[TDBXPropertyNames.MetaDataAssemblyLoader] := 'Borland.Data.TDBXMsSqlMetaDataCommandFactory,Borland.Data.DbxMSSQLDriver,Version=15.0.0.0,Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b';
Values[TDBXPropertyNames.GetDriverFunc] := 'getSQLDriverMSSQL';
Values[TDBXPropertyNames.LibraryName] := 'dbxmss.dll';
Values[TDBXPropertyNames.VendorLib] := 'sqlncli10.dll';
Values[TDBXPropertyNames.HostName] := 'ServerName';
Values[TDBXPropertyNames.Database] := 'Database Name';
Values[TDBXPropertyNames.MaxBlobSize] := '-1';
Values['LocaleCode'] := '0000';
Values[TDBXPropertyNames.IsolationLevel] := 'ReadCommitted';
Values['OSAuthentication'] := 'False';
Values['PrepareSQL'] := 'True';
Values[TDBXPropertyNames.UserName] := 'user';
Values[TDBXPropertyNames.Password] := 'password';
Values['BlobSize'] := '-1';
Values[TDBXPropertyNames.ErrorResourceFile] := '';
Values['OS Authentication'] := 'False';
Values['Prepare SQL'] := 'True';
Values[TDBXPropertyNames.ConnectTimeout] := '30';
// Not adding connection pooling to the default driver parameters
end;
var
InternalConnectionFactory: TDBXMemoryConnectionFactory;
initialization
TDBXDriverRegistry.RegisterDriverClass('MSSQL_NoINI', TDBXInternalDriver);
InternalConnectionFactory := TDBXMemoryConnectionFactory.Create;
InternalConnectionFactory.Open;
TDBXConnectionFactory.SetConnectionFactory(InternalConnectionFactory);
end.
上記のメソッドはプロジェクト(.dprファイル)に含まれており、ドライバーを自己登録します。次の方法では、これを利用してTSQLConnection
実行時(DataSnapサーバーの起動時)に(sqlcon)をセットアップします。
procedure SetupConnection(const hostname, port, dbname, username, password, maxcon: string);
begin
if sqlcon.Connected then
Exit;
// Our custom driver -- does not use DBXDrivers.ini
sqlcon.Params.Clear;
sqlcon.DriverName := 'MSSQL_NoINI';
sqlcon.VendorLib := sqlcon.Params.Values[TDBXPropertyNames.VendorLib];
sqlcon.LibraryName := sqlcon.Params.Values[TDBXPropertyNames.LibraryName];
sqlcon.GetDriverFunc := sqlcon.Params.Values[TDBXPropertyNames.GetDriverFunc];
sqlcon.Params.Values[TDBXPropertyNames.HostName] := hostname;
sqlcon.Params.Values[TDBXPropertyNames.Port] := port;
sqlcon.Params.Values[TDBXPropertyNames.Database] := dbname;
sqlcon.Params.Values[TDBXPropertyNames.UserName] := username;
sqlcon.Params.Values[TDBXPropertyNames.Password] := password;
sqlcon.Params.Values[TDBXPropertyNames.DelegateConnection] := DBXPool.sDriverName;
sqlcon.Params.Values[DBXPool.sDriverName + '.' + TDBXPoolPropertyNames.MaxConnections] := maxcon;
sqlcon.Params.Values[DBXPool.sDriverName + '.' + TDBXPoolPropertyNames.MinConnections] := '1';
sqlcon.Params.Values[DBXPool.sDriverName + '.' + TDBXPoolPropertyNames.ConnectTimeout] := '1000';
sqlcon.Params.Values[DBXPool.sDriverName + '.' + 'DriverUnit'] := DBXPool.sDriverName;
sqlcon.Params.Values[DBXPool.sDriverName + '.' + 'DelegateDriver'] := 'True';
sqlcon.Params.Values[DBXPool.sDriverName + '.' + 'DriverName'] := DBXPool.sDriverName;
end;
これらの設定のいずれかが、コンポーネントを台無しにして、TSQLConnection
データセットをキャッシュし、最新のTSQLQuery
コンポーネントが実行したものの代わりにそれらを返すようにしている可能性がありますか?
どんな助けでも大歓迎です。お分かりのように、これは私を夢中にさせています!
ありがとう、ジェームズ