我正在使用Synopse的SQLite实现,但我仍然坚持使用以下代码。在表单构造函数中,我创建了一个数据库模型,其中有两个表Task
和Comment
以及一个表TaskComments
,其中任务注释的关系为1:N。我可以将行添加到TaskComments
表中(Button1.OnClick事件为它添加一个任务和两个注释)但我不知道如何获取此任务的注释。
有人可以建议我如何获取某一行的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.
非常感谢
答案 0 :(得分:7)
你应该在官方的mORMot论坛上发布这个帖子,这个日子里没有像其他土拨鼠一样睡觉......但是在SO中看到这样的问题非常好!
首先,一些一般性说明:
UTF8ToString
代替UTF8ToWideString
功能; try..finally
块:例如如果TComment.CreateAndPrepare
构造函数失败并引发异常,您将永远无法访问FreeAndNil(Task)
代码,因此您将泄漏内存; FreeAndNil()
是非常危险的 - 你可能会被解剖!FSQLModel
应公开,并在所有数据库时间内生效; TSQLRestClientDB
3d参数(服务器型号)应为零; FormDestroy
,但这不是主要内容; 关于您的代码,事实上,正如文档中所述,TSQLRecordMany
子类必须至少有两个已发布的属性,名为Source
和{{1按惯例:
- 默认情况下,只能创建两个TSQLRecord(即INTEGER)字段, 名为“Source”和“Dest”,第一个指向源记录(一个 使用TSQLRecordMany发布的属性)和第二个到目标记录 ...
- 在所有情况下,在leat两个'Source'和'Dest'发布的属性必须 在任何TSQLRecordMany后代中声明为TSQLRecord子节点 因为他们总是需要“多对多”的关系
然后,它应该按预期工作:
Dest
请注意, TTaskComments = class(TSQLRecordMany)
private
FSource: TTask;
FDest: TComment;
published
property Source: TTask read FSource;
property Dest: TComment read FDest;
end;
方法仅将FillMany()
和Source
填充为ID,因此您无法直接获取Dest
或Source.TaskName
。你必须使用,例如用于检索所需字段的Dest.CommentText
方法。请参阅有关该方法的文档,或阅读DestGetJoined
单元的TestMany
方法中的TTestSQLite3Engine._TSQLRestClientDB
程序。
您还可以查看“自动JOIN查询”新功能(在1.16主干中):它将为您提供查询。请参阅this article。