3

ADO データベース コンポーネントを使用して、SQL データベース (MySQL) に接続する最初の Delphi アプリケーションを書き始めています。後で SQL クエリを作成するときに簡単に参照できるように、フィールドの名前をデータベースに保存する最善の方法はないかと考えました。

まず第一に、私はそれらを単純な定数にしましたc_UserTable_Username, c_UserTable_Passwordが、それは物事を行うのに特に良い方法ではないと判断したので、今はそれらを定数レコードに保存しています.

type
   TUserTable = record
     TableName : String;
     Username : String;
     Password : String;
 end;

const
UserTable : TUserTable =
    (
      TableName : 'users';
      Username : 'Username';
      Password : 'Password';
    );

これにより、次のようなステートメントを作成できます。

query.SQL.Add('SELECT ' + UserTable.Username + ' FROM ' + UserTable.TableName);

フィールド名などのハードコーディングについて心配する必要はありません。

私は今、問題に遭遇しましたが、テーブル フィールドを循環させたい場合 (たとえば、20 個ほどのフィールドがある場合) はできません。すべてのフィールドのレコード参照を手動で入力する必要があります。

私が知りたいのは、すべてのフィールド名を一度に、または個別に反復する方法があるかどうかです。それとも私はこれについて間違った方法をとっていますか?おそらく、私はそれらをこのように保管するべきではありませんか?

また、GetAllUsers、GetAllProducts など、さまざまな SQL ステートメントのメソッドを基本的に保持する「データベース」クラスを作成しました。私は多くの Delphi/SQL チュートリアルを見てきましたが、クエリの実行方法を示す以上のことはしていないようです。

私は少し迷っているだけだと思います。どんな助けも大歓迎です。ありがとう :)

4

5 に答える 5

3

クエリを RESOURCESTRING として保存することもできます。これにより、後でリソース エディターを使用してクエリを編集できます (必要な場合)。

RESOURCESTRING
  rsSelectFromUsers = 'SELECT USERNAME FROM USERS ';

データベースクラスのアプローチは非常にうまく機能します。私はいくつかのプロジェクトでそれを行い、データセットを含むオブジェクトへのインターフェイスを返しました...これの利点は、返されたインターフェイス変数が範囲外になると、データセットが閉じられてクリアされることです。

于 2009-03-05T21:55:11.050 に答える
2

さて、あなたはフィールド名をハードコーディングしています。クエリ自体ではなく、const にハードコードするだけです。それが実際に何かを改善するかどうかはわかりません。フィールドを反復する限り、これを試してください:

var
  Field: TField;
begin
  for Field in query.Fields do begin
     // do stuff with Field
  end;
end;

「データベース」クラスを作成するのではなく、おそらく TDataModule を使用します。これは、設計時に対話的にクエリを設計できることを除いて、クラスとほぼ同じことを行います。必要なメソッドを DataModule に置くことができます。

これにより、永続的な TField をインスタンス化することも非常に簡単になります (そのトピックのヘルプを参照してください)。const を使用してフィールド名を格納するよりも、好みに合ったソリューションを見つけることができます。

于 2009-03-05T14:51:44.423 に答える
1

トピックから少し外れているかもしれませんが、RemObjects のData Abstractを使用できます。

于 2009-06-05T19:14:55.040 に答える
1

実際に図のようにデータベース クラスを使用する場合は、D2007 以降でレコードに関数を含める機能を検討してください。

たとえば、あなたの例は次のようになります。

type
   TUserTable = record
     TableName : String;
     Username : String;
     Password : String;
     function sqlGetUserName(where:string=''):string;
   end;

const
UserTable : TUserTable =
    (
      TableName : 'users';
      Username : 'Username';
      Password : 'Password';
    );

function TUserTable.sqlGetUserName(where:string=''): string;
begin
if where='' then result := Format('SELECT %s from %s', [userName, tableName])
else             result := Format('SELECT %s from %s where %s', [userName, tableName, where]);
end;

これにより、次のことが可能になります。

query.SQL.add(userTable.sqlGetUserName);

また

query.SQL.add(userTable.sqlGetUserName(Format('%s=%s', [userTable.userName,'BOB']));

あなたが説明したように、SQLを直接使用することはあまりお勧めしません。私の意見では、テーブルへの直接の SQL 呼び出しを行うべきではありません。これにより、UI とデータベース (存在してはならない) の間に多くの結合が導入され、テーブルの直接変更に高レベルのセキュリティを設定できなくなります。

すべてをストアド プロシージャにラップし、すべてのデータベース コードをデータ モジュールにカプセル化する DB インターフェイス クラスを用意します。データ モジュールからデータベース対応コンポーネントへの直接リンクを引き続き使用できます。リンクの前に DM 名を付けるだけです。

たとえば、次のようなクラスを作成したとします。

type
   TDBInterface = class
      private
         function q(s:string):string; //just returns a SQL quoted string
      public
         procedure addUser(userName:string; password:string);
         procedure getUser(userName:string);
         procedure delUser(userName:string);

         function testUser:boolean;

         procedure testAllDataSets;
      end;

function TDBInterface.q(s:string):string;
begin
result:=''''+s+'''';
end;

procedure TDBInterface.addUser(userName:string; password:string);
begin
cmd.CommandText:=Format( 'if (select count(userName) from users where userName=%s)=0 '+
                         'insert into users (userName, password) values (%s,%s) '+
                         'else '+
                         'update users set userName=%s, password=%s where userName=%s',
                         [q(userName), q(userName), q(password), q(userName), q(password), q(userName)]);
cmd.Execute;
end;

procedure TDBInterface.getUser(userName:string);
begin
qry.SQL.Add(Format('select * from users where userName=%s', [q(userName)]));
qry.Active:=true;
end;

procedure TDBInterface.delUser(userName:string);
begin
cmd.CommandText:=Format('delete from users where userName=%s',[userName]);
cmd.Execute;
end;

procedure TDBInterface.testAllDataSets;
begin
assert(testUser);
end;

function TDBInterface.testUser: boolean;
begin
result:=false;

   addUser('99TEST99','just a test');
   getUser('99TEST99');
   if qry.IsEmpty then exit;
   if qry.FieldByName('userName').value<>'99TEST99' then
      exit;
   delUser('99TEST99');
   if qry.IsEmpty then
      result:=true;
end;

これで、データ インターフェイスで何らかの形式の単体テストを実行できるようになりました。UI から SQL を削除すると、状況が改善されます。ただし、インターフェイス コードにはまだ多くの醜い SQL が含まれているため、それをストアド プロシージャに移動すると、次のようになります。

type
   TDBInterface = class
      public
         procedure addUser(userName:string; password:string);
         procedure getUser(userName:string);
         procedure delUser(userName:string);

         function testUser:boolean;

         procedure testAllDataSets;
      end;

procedure TDBInterface.addUser(userName:string; password:string);
begin
cmd.CommandText:='usp_addUser;1';
cmd.Parameters.Refresh;
cmd.Parameters.ParamByName('@userName').Value:=userName;
cmd.Parameters.ParamByName('@password').Value:=password;
cmd.Execute;
cmd.Execute;
end;

procedure TDBInterface.getUser(userName:string);
begin
sproc.Parameters.ParamByName('@userName').Value:=userName;
sproc.Active:=true;
end;

procedure TDBInterface.delUser(userName:string);
begin
cmd.CommandText:='usp_delUser;1';
cmd.Parameters.Refresh;
cmd.Parameters.ParamByName('@userName').Value:=userName;
cmd.Execute;
end;

これらの関数の一部を ADO スレッドに移動すると、UI はユーザーの追加または削除が別のプロセスで行われることを認識しなくなります。これらは非常に単純な操作なので、プロセスが完了したときに親に通知するなどの便利なことをしたい場合 (たとえば、追加/削除/更新が発生した後にユーザー リストを更新するため)、それをスレッドにコーディングする必要があります。モデル。

ところで、追加コードのストアド プロシージャは次のようになります。

create procedure [dbo].[usp_addUser](@userName varchar(20), @password varchar(20)) as
if (select count(userName) from users where userName=@userName)=0
   insert into users (userName, password) values (@userName,@password)
else 
   update users set userName=@userName, password=@password where userName=@userName

また、ちょっとした免責事項: この投稿はかなり長いので、ほとんどを確認しようとしましたが、どこかで何かを見落としている可能性があります。

于 2009-03-06T02:01:59.460 に答える
0

データセットの分析(DelphiおよびKylix)で略奪する

このコードは、テーブルのメタデータを操作する良い例です。フィールド名を取得してから、ベースユニット/またはそのインターフェイス部分を作成できるコードジェネレーターを作成できます。

于 2009-06-05T13:12:16.437 に答える