3

SynopseのSQLite実装で遊んでいますが、次のコードで行き詰まっています。Taskフォームコンストラクターで、タスクコメント用に2つのテーブルとComment1つのテーブルTaskCommentsの関係が1:Nのデータベースモデルを作成します。テーブルに行を追加することはできますがTaskComments(Button1.OnClickイベントは1つのタスクと2つのコメントを追加します)、このタスクのコメントを取り戻す方法がわかりません。

特定の行のN行を取得する方法(この場合はタスクのコメントを取得する方法)を誰かに提案できますか?

unit SynopseSQLiteTestUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, SynCommons, SQLite3, SQLite3Commons, StdCtrls;

type
  TTask = class(TSQLRecord)
  private
    FTaskName: RawUTF8;
    FTaskCreated: TDateTime;
  published
    property TaskName: RawUTF8 read FTaskName write FTaskName;
    property TaskCreated: TDateTime read FTaskCreated write FTaskCreated;
  end;

  TComment = class(TSQLRecord)
  private
    FCommentText: RawUTF8;
    FCommentCreated: TDateTime;
  published
    property CommentText: RawUTF8 read FCommentText write FCommentText;
    property CommentCreated: TDateTime read FCommentCreated write FCommentCreated;
  end;

  TTaskComments = class(TSQLRecordMany)
  private
    FTask: TTask;
    FComment: TComment;
  published
    property Task: TTask read FTask;
    property Comment: TComment read FComment;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    Memo2: TMemo;
    Memo3: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    FDatabase: TSQLRestClientURI;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  SQLModel: TSQLModel;
begin
  SQLModel := TSQLModel.Create([
    TTask,
    TComment,
    TTaskComments
  ]);
  FDatabase := TSQLRestClientDB.Create(SQLModel, SQLModel, ChangeFileExt(Application.ExeName,'.db3'), TSQLRestServerDB);
  TSQLRestClientDB(FDatabase).Server.CreateMissingTables(0);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Task: TTask;
  TaskID: Integer;
  Comment: TComment;
  CommentID: Integer;
  TaskComments: TTaskComments;
begin
  Task := TTask.Create;
  Comment := TComment.Create;
  TaskComments := TTaskComments.Create;

  try
    Task.TaskName := StringToUTF8('Task Name');
    Task.TaskCreated := Now;
    TaskID := FDatabase.Add(Task, True);

    Comment.CommentText := StringToUTF8('Comment Text 1');
    Comment.CommentCreated := Now;
    CommentID := FDatabase.Add(Comment, True);

    TaskComments.ManyAdd(FDatabase, TaskID, CommentID);

    Comment.CommentText := StringToUTF8('Comment Text 2');
    Comment.CommentCreated := Now;
    CommentID := FDatabase.Add(Comment, True);

    TaskComments.ManyAdd(FDatabase, TaskID, CommentID, True);

  finally
    FreeAndNil(Task);
    FreeAndNil(Comment);
    FreeAndNil(TaskComments);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Task: TTask;
  Comment: TComment;
  TaskComments: TTaskComments;
begin
  Memo1.Clear;
  Memo2.Clear;
  Memo3.Clear;

  // here I want to select task with ID = 1, that's fine
  Task := TTask.CreateAndFillPrepare(FDatabase, 'ID = 1');
  // here I want to select all comments, that's fine
  Comment := TComment.CreateAndFillPrepare(FDatabase, '');
  // here I want to create the task comments, ok
  TaskComments := TTaskComments.Create;

  try
    // here I'm filling the memo boxes with the task and all comments, ok
    while Task.FillOne do
      Memo1.Lines.Add(UTF8ToWideString(Task.TaskName));
    while Comment.FillOne do
      Memo2.Lines.Add(UTF8ToWideString(Comment.CommentText));

    // here I'm trying to get all comments for task with ID = 1
    // but the FillOne function returns always False, what means, that
    // I don't get any row fetched
    TaskComments.FillMany(FDatabase, 1);
    while TaskComments.FillOne do
      Memo3.Lines.Add(UTF8ToWideString(TaskComments.Task.TaskName) + '; ' + UTF8ToWideString(TaskComments.Comment.CommentText));

  finally
    FreeAndNil(Task);
    FreeAndNil(Comment);
    FreeAndNil(TaskComments);
  end;
end;

end.

どうもありがとう

4

1 に答える 1

7

最近他のマーモットのように眠っていない公式のmORMotフォーラムにこれを投稿するべきでした...しかし、SOでそのような質問を見るのはとてもうれしいです!

まず第一に、いくつかの一般的な注意事項:

  • 関数UTF8ToStringの代わりに使用する方がよいでしょう。UTF8ToWideString
  • オブジェクトインスタンスを作成する場合は、ネストされたtry..finallyブロックを使用することをお勧めします。たとえば、TComment.CreateAndPrepareコンストラクターが失敗して例外が発生した場合、コードに到達することはないため、FreeAndNil(Task)メモリがリークします。
  • Delphiコミュニティでは、当時の使用FreeAndNil()は非常に危険です。気を付けてください。
  • メインFSQLModelは公開し、データベースのすべての時間に公開する必要があります。
  • TSQLRestClientDB3dパラメーター(サーバーモデル)はnilである必要があります。
  • AFormDestroyはメモリを解放するために必要ですが、ここでは重要なポイントではありません。

実際、ドキュメントに記載されているように、コードについては、サブクラスTSQLRecordManyには、慣例により、とという名前の少なくとも2つの公開されたプロパティが必要です。SourceDest

  • デフォルトでは、「Source」と「Dest」という名前の2つのTSQLRecord(つまり、INTEGER)フィールドのみを作成する必要があります。最初のフィールドはソースレコード(TSQLRecordMany公開プロパティを持つレコード)を指し、2番目のフィールドは宛先レコードを指します...
  • すべての場合において、少なくとも2つの「Source」および「Dest」公開プロパティは、「多対多」関係に常に必要になるため、TSQLRecordManyの子孫でTSQLRecordの子として宣言する必要があります。

次に、期待どおりに機能するはずです。

  TTaskComments = class(TSQLRecordMany)
  private
    FSource: TTask;
    FDest: TComment;
  published
    property Source: TTask read FSource;
    property Dest: TComment read FDest;
  end;

また、このFillMany()メソッドはIDとしてSourceとを入力するだけDestなので、ここでまたはを直接取得することはできませSource.TaskNameDest.CommentText。代わりにDestGetJoined、必要なフィールドを取得するメソッドなどを使用する必要があります。その方法に関するドキュメントを参照するか、ユニットの方法のTestMany手順をお読みください。TTestSQLite3Engine._TSQLRestClientDBSQLite3.pas

また、「自動JOINクエリ」の新機能(1.16トランク内)を確認することもできます。これにより、自分だけのクエリが作成されます。この記事を参照してください。

于 2012-01-23T17:07:46.980 に答える