You are not logged in.
ok thanks
now I have these tables and when I Server.CreateMissingTables in SQLite function in MSSQL and an exception occurs when I create the user table or role etc.. I think it's because it refers to the group of roles and these tables do not exist yet.
I can create tables "TSQLRecordMany" and if you like I have to write code?thanks
type
TSQLUser =Class;
TSQLRole =Class;
TSQLGruppo =Class;
TSQLGroupRoles = class;
TSQLUserGroups = Class;
TSQLUserRoles = class;
TSQLFile = class(TSQLRecordExternal)// class(TSQLRecordSigned)
private
Check:Boolean;
public
fName: RawUTF8;
fModified: TTimeLog;
fCreated: TTimeLog;
fPicture: TSQLRawBlob;
fKeyWords: RawUTF8;
fLabel :RawUTF8;
fImageIndex: Integer;
function CheckValues(Reference: TSQLRecord): boolean;virtual;
function CopyFrom(ARec: TSQLRecord): TSQLRecord;
procedure CopyTo(var ARec:TSQLRecord);
published
property Name: RawUTF8 read fName write fName;
property Created: TTimeLog read fCreated write fCreated;
property Modified: TTimeLog read fModified write fModified;
property Picture: TSQLRawBlob read fPicture write fPicture;
property KeyWords: RawUTF8 read fKeyWords write fKeyWords;
// property SignatureTime;
// property Signature;
property Label_: RawUTF8 read fLabel write fLabel;
property ImageIndex: Integer read FImageIndex write FImageIndex;
end;
TSQLUser = class(TSQLFile)
private
fRoles: TSQLUserRoles;
fLogin, fPassword: RawUTF8;
fSubName: RawUTF8;
fGroups: TSQLUserGroups;
public
property Roles: TSQLUserRoles read fRoles write fRoles;
property Groups: TSQLUserGroups read fGroups write fGroups;
published
property Login: RawUTF8 read fLogin write fLogin;
property Password: RawUTF8 read fPassword write SetPassword;
property SubName: RawUTF8 read fSubName write fSubName;
end;
TSQLGruppo = class(TSQLFile)
private
fUsers: TSQLUserGroups;
fRoles: TSQLGroupRoles;
public
published
property Users: TSQLUserGroups read fUsers write fUsers;
property Roles: TSQLGroupRoles read fRoles write fRoles;
end;
TSQLRole = class(TSQLFile)
private
fUsers: TSQLUserRoles;
fGroups: TSQLGroupRoles;
public
published
property Users: TSQLUserRoles read fUsers write fUsers;
property Groups: TSQLGroupRoles read fGroups write fGroups;
end;
TSQLUserGroups = class(TSQLRecordMany)
private
fValidUntil: TTimeLog;
fSource: TSQLUser;
fDest: TSQLGruppo;
published
property Source: TSQLUser read fSource;
property Dest: TSQLGruppo read fDest;
end;
TSQLUserRoles = class(TSQLRecordMany)
private
fValidUntil: TTimeLog;
fSource: TSQLUser;
fDest: TSQLRole;
published
property ValidUntil: TTimeLog read fValidUntil write fValidUntil;
property Source: TSQLUser read fSource;
property Dest: TSQLRole read fDest;
end;Sorry but I am not yet clear. I had to insert this line "fClient: = TSQLRestClientDB.Create (Model, nil, 'test.db3', TSQLRestServerDB)," because the tables were created in MSSQL. I do not understand why I need to create a db3 "test.db3" and then work with MSSQL. But where the data are saved?
constructor TFileServer.Create(const ServerName,SeverPort: AnsiString;const aFilename: AnsiString);
var
i:Integer;
fClient: TSQLRestClientDB;
fConnection: TSQLDBConnectionProperties;
Start, Updated: TTimeLog;
begin
try
Props := TOleDBMSSQLConnectionProperties.Create('SQL2008\SQL2008',',MyDB','','');
inherited Create(CreateFileModel(self));
for i := 0 to high(Model.Tables) do
VirtualTableExternalRegister(Model, TSQLRecordExternalClass(Model.Tables[i]),Props,'');
try
fClient := TSQLRestClientDB.Create(Model,nil,'test.db3',TSQLRestServerDB);
Start := fClient.ServerTimeStamp;
fClient.Server.StaticVirtualTableDirect := StaticVirtualTableDirect;
fClient.Server.CreateMissingTables;
finally
fClient.Free;
end;
...thanks
If I derive classes from TSQLRecordExternal means I have to modify the code written for the model, I had understood that it not necessary to modified the original classes
TSQLFile = class(TSQLRecordSigned) modified to TSQLFile = class(TSQLRecordExternal)
private
...
end
// user of our system
TSQLUser = class(TSQLFile)
private
...
end//VirtualTableExternalRegister(fModel,TSQLRecordPeopleExt,fConnection,'PeopleExternal');
function CreateFileModel(Owner: TSQLRest): TSQLModel;
var Classes: array[0..high(FileTabs)] of TSQLRecordClass;
i: integer;
begin
for i := 0 to high(FileTabs) do
Classes[i] := FileTabs[i].Table;
Model := TSQLModel.Create(Classes);
Model.Owner := Owner;
Model.SetEvents(TypeInfo(TFileEvent));
Result := Model;
end;
constructor TFileServer.Create(const ServerName,SeverPort: AnsiString;const aFilename: AnsiString);
var
i :Integer;
begin
try
writeln(format('file server is %s',[aFilename]));
inherited Create(CreateFileModel(self),aFilename);
{$ifdef MSSQL}
Props := TOleDBMSSQLConnectionProperties.Create('SQL2008\SQL2008',MyDB','','');
inherited Create(CreateFileModel(self))
for i := 0 to high(Model.Tables) do
VirtualTableExternalRegister(Model, Model.Tables[i],Props,'');
{$endif}
CreateMissingTables(0); // ExeVersion.Version.Version32);
Server := TSQLite3HttpServer.Create(SeverPort,[self],ServerName);
finally
end;
end;way is it correct? or the following code is not needed?
...
for i := 0 to high(Model.Tables) do
VirtualTableExternalRegister(Model, Model.Tables[i],Props,'');
...thanks
Sorry,
I read the documentation but I have not found a consistent example to make me understand how to implement the connection using MSSQL and my model without adding new classes.
I wrote the following routine that uses the server to connect to SQLite files, what should I add to make sure that the tables are created depending on the model?
constructor TFileServer.Create(const ServerName,SeverPort: AnsiString;const aFilename: AnsiString);
begin
try
writeln(format('file server is %s',[aFilename]));
inherited Create(CreateFileModel(self),aFilename);
CreateMissingTables(0); // ExeVersion.Version.Version32);
Server := TSQLite3HttpServer.Create(SeverPort,[self],ServerName);
{$ifdef MSSQL}
Props := TOleDBMSSQLConnectionProperties.Create('SQL2008\SQL2008',MyDB','','');
inherited Create(CreateFileModel(self))
{$endif}
finally
end;
end;thanks
I forgot to tell you that I work in a network is not the Internet, change anything?
ok thanks, before, I try to connect to MSSQL and then I will do all the tests that you suggested
I created a client \ server by using it your own framework.
I have used the SQLite as database server, but the client operations are too slow, now I want to migrate to MSSQL and I read that it's possible.
I ask if there is a procedure that automatically creat all the tables in MSSQ ( with "CreateMissingTables") or I have to map every single class of my model with the MSSQL tables?
I only found this example:
// ! Props := TOleDBMSSQLConnectionProperties.Create('.\SQLEXPRESS','AdventureWorks2008R2','','');
// ! Model := TSQLModel.Create([TSQLCustomer],'root');
// ! VirtualTableExternalRegister(Model,TSQLCustomer,Props,'Sales.Customer');Thanks corchi 72
Filling this with "USETMSPACK" I have an error in the unit SynTaskDialog, I moved the directive "{$ endif} USETMSPACK" after the definition "TTaskDialogEx" and two other points.
Thanks corchi72
Hello, I have a question to ask yourself, I have a class that has TSQLQVW a property called "connection" that refers to another class TSQLConnection, what is the right way to write the class TSQLQVW not have to go around I have written below.
Is there another solution?
I did not want to use the usual class "TSQLRecordMany" to create the relationship because it is a type of relationship one to many but just a one to one
TSQLQvwConnections= class(TSQLRecordMany)
private
fSource: TSQLQvw;
fDest: TSQLConnection;
published
property Source: TSQLQvw read fSource;
property Dest: TSQLConnection read fDest;
end;This is the code that I implemented and it works but I think it's the right solution
TSQLConnection = class(TSQLFile)
private
fOwner: RawUTF8;
fEnabled: boolean;
fConnectionString:RawUTF8;
...
published
property Owner: RawUTF8 read fOwner write fOwner;
property Enabled: boolean read fEnabled write fEnabled;
property ConnectionString:RawUTF8 read fConnectionString write fConnectionString;
end;
TSQLQvw = class(TSQLFile)
private
fOwner: RawUTF8;
fEnabled: boolean;
...
fConnection: TSQLConnection;
FConnectionID: Integer;
procedure SetConnectionID(const Value: Integer);
function GetConnection: TSQLConnection;
procedure SetConnection(const Value: TSQLConnection);
property Connection: TSQLConnection read GetConnection write SetConnection;
published
property Owner: RawUTF8 read fOwner write fOwner;
property Enabled: boolean read fEnabled write fEnabled;
...
property ConnectionID:Integer read FConnectionID write SetConnectionID;
end;
var
Model: TSQLModel;
currentClient : TSQLRestClientUri;
....
implementation
procedure TSQLQvw.SetConnection(const Value: TSQLConnection);
begin
FConnectionID := Value.ID;
end;
procedure TSQLQvw.SetConnectionID(const Value: Integer);
begin
FConnectionID := Value;
end;
function TSQLQvw.GetConnection: TSQLConnection;
begin
result := TSQLConnection.Create(currentClient,FConnectionID);
end; I developed two solutions and the second is faster than a second, but I also decided to include the first solution in my program because it is in line with your framework, and is more understandable and maintainable.
1) solution:
function TSQLUser.LoadQvws(ClientDB: TSQLRestClientUri): TSQLQvw;
var
fIds,fIds4: TIntegerDynArray;
fIdsUser,fIdsGroup,fIdsRole,fIdsGroupRoles:TIntegerDynArray;
i,j:Integer;
AGroupQvws: TSQLGroupQvws;
ARoleQvws : TSQLRoleQvws;
begin
result := nil;
SetLength(fIds4,0);
fGroups.DestGet(ClientDB, self.ID, fIdsGroup);
AGroupQvws := TSQLGroupQvws.CreateAndFillPrepare(ClientDB,IntegerDynArrayToCSV(fIdsGroup,length(fIdsGroup),'Source IN (',')'));
while AGroupQvws.FillOne do
AddInteger(fIds4,AGroupQvws.Dest.ID ,true);
AGroupQvws.FillClose;
fRoles.DestGet(ClientDB, self.ID, fIdsRole);
fIdsGroupRoles:=ReadGroupRoles(ClientDB,fIdsGroup);
AddSortedIntegerArray(fIdsGroupRoles,fIdsRole);
ARoleQvws := TSQLRoleQvws.CreateAndFillPrepare(ClientDB,IntegerDynArrayToCSV(fIdsRole,length(fIdsRole),'Source IN (',')'));
while ARoleQvws.FillOne do
AddInteger(fIds4,ARoleQvws.Dest.ID ,true);
ARoleQvws.FillClose;
fQvws.DestGet(ClientDB, self.ID, fIds);
for I := 0 to Length(fIds) - 1 do
begin
AddInteger(fIds4,fIds[i] ,true);
end;
if Length(fIds4)>0 then
begin
SetLength(fIds,Length(fIds4));
CopyAndSortInteger(Pointer(fIds4),Length(fIds4),fIds);
result := TSQLQvw.CreateAndFillPrepare(ClientDB, fIds);
end;
end;2) solution:
function TSQLUser.LoadQvws(ClientDB: TSQLRestClientUri): TSQLQvw;
var
fIds,fIds4: TIntegerDynArray;
fIdsUser,fIdsGroup,fIdsRole,fIdsGroupRoles:TIntegerDynArray;
i,j:Integer;
fSQLSelect: RawUTF8;
fSQLWhereGroups: RawUTF8;
fSQLLeftJoinGroups: RawUTF8;
fSQLWhereRoles: RawUTF8;
fSQLLeftJoinRoles: RawUTF8;
fSQLWhereUser: RawUTF8;
fSQLLeftJoinUser: RawUTF8;
fSQLWhere: RawUTF8;
fSQLLeftJoin: RawUTF8;
aTable: TSQLTable;
begin
fIdsGroup := ReadGroups(ClientDB);
if Length(fIdsGroup)>0 then
begin
fSQLLeftJoinGroups := format('left join %s on %s.Dest= %s.ID',[TSQLGroupQvws.SQLTableName,TSQLGroupQvws.SQLTableName,TSQLQvw.SQLTableName]);
fSQLWhereGroups := format('%s.%s',[TSQLGroupQvws.SQLTableName,IntegerDynArrayToCSV(fIdsGroup,length(fIdsGroup),'Source IN (',')')]);
fSQLWhere := fSQLWhereGroups;
fSQLLeftJoin := fSQLLeftJoinGroups;
end;
fIdsRole := ReadRoles(ClientDB);
fIdsGroupRoles:=ReadGroupRoles(ClientDB,fIdsGroup);
AddSortedIntegerArray(fIdsGroupRoles,fIdsRole);
if Length(fIdsRole)>0 then
begin
fSQLLeftJoinRoles := format('left join %s on %s.Dest= %s.ID',[TSQLRoleQvws.SQLTableName,TSQLRoleQvws.SQLTableName,TSQLQvw.SQLTableName]);
fSQLWhereRoles := format('%s.%s',[TSQLRoleQvws.SQLTableName,IntegerDynArrayToCSV(fIdsRole,length(fIdsRole),'Source IN (',')')]);
if fSQLWhere<>'' then fSQLWhere := fSQLWhere + ' or ';
fSQLWhere := fSQLWhere + fSQLWhereRoles;
if fSQLLeftJoin<>'' then fSQLLeftJoin := fSQLLeftJoin + ' ';
fSQLLeftJoin := fSQLLeftJoin +fSQLLeftJoinRoles;
end;
fQvws.DestGet(ClientDB, self.ID, fIds);
if Length(fIds)>0 then
begin
fSQLLeftJoinUser := format('left join %s on %s.Dest= %s.ID',[TSQLUserQvws.SQLTableName,TSQLUserQvws.SQLTableName,TSQLQvw.SQLTableName]);
fSQLWhereUser := format('%s.Source = %d',[TSQLUserQvws.SQLTableName,self.ID]);
if fSQLWhere<>'' then fSQLWhere := fSQLWhere + ' or ';
fSQLWhere := fSQLWhere + fSQLWhereUser;
if fSQLLeftJoin<>'' then fSQLLeftJoin := fSQLLeftJoin + ' ';
fSQLLeftJoin := fSQLLeftJoin +fSQLLeftJoinUser;
end;
fSQLSelect := format('Select %s from %s %s where %s group by %s.ID', [TSQLQvw.RecordProps.SQLTableSimpleFields[true,true],TSQLQvw.SQLTableName,fSQLLeftJoin,fSQLWhere,TSQLQvw.SQLTableName]);
aTable := ClientDB.ExecuteList([TSQLQvw],fSQLSelect);
Result := TSQLQvw.Create;
if aTable = nil then exit;
Result.FillPrepare(aTable);This function is used in both solutions
function TSQLUser.ReadGroupRoles(ClientDB: TSQLRestClientUri;fIdsGroup:TIntegerDynArray):TIntegerDynArray;
var
fIdsRole:TIntegerDynArray;
AGruppo:TSQLGruppo;
AGroupRoles:TSQLGroupRoles;
begin
SetLength(fIdsRole,0);
AGroupRoles := TSQLGroupRoles.CreateAndFillPrepare(ClientDB,fIdsGroup);
while AGroupRoles.FillOne do
AddInteger(fIdsRole,AGroupRoles.Dest.ID,false);
result := fIdsRole
end;Thanks corchi
How to convert this Query in a format string (fSQLWhere) for to create a TSQLQvw.CreateAndFillPrepare(ClientDB, fSQLWhere) correctly.
I have to get a resultset of TSQLQvw
TSQLGroupRoles = class(TSQLRecordMany)
private
fSource: TSQLGruppo;
fDest: TSQLRole;
published
property Source: TSQLGruppo read fSource;
property Dest: TSQLRole read fDest;
end;
TSQLUserQvws = class(TSQLRecordMany)
private
fSource: TSQLUser;
fDest: TSQLQvw;
published
property Source: TSQLUser read fSource;
property Dest: TSQLQvw read fDest;
end;
TSQLRoleQvws = class(TSQLRecordMany)
private
fSource: TSQLRole;
fDest: TSQLQvw;
published
property Source: TSQLRole read fSource;
property Dest: TSQLQvw read fDest;
end;
TSQLGroupQvws = class(TSQLRecordMany)
private
fSource: TSQLGruppo;
fDest: TSQLQvw;
published
property Source: TSQLGruppo read fSource;
property Dest: TSQLQvw read fDest;
end;
TSQLQvw = class(TSQLFile)
private
...
published
property Users: TSQLUserQvws read fUsers;
property Groups: TSQLGroupQvws read fGroups;
property Roles: TSQLRoleQvws read fRoles;
end;
function TSQLUser.LoadQvws(ClientDB: TSQLRestClientUri): TSQLQvw;
var
fIdsQvw,fIdsGroup,fIdsRole:TIntegerDynArray;
begin
fQvws.DestGet(ClientDB, self.ID, fIdsQvw);
fGroups.DestGet(ClientDB, self.ID, fIdsGroup);
fRoles.DestGet(ClientDB, self.ID, fIdsRole);
result := TSQLQvw.CreateAndFillPrepare(ClientDB,
"
SELECT Qvw.ID,Name,Description FROM Qvw
left join GroupQvws
on GroupQvws.Dest= Qvw.ID
left join RoleQvws
on RoleQvws.Dest= Qvw.ID
WHERE GroupQvws.Source IN (2 (=> fIdsGroup) ) or RoleQvws.Source IN (1,2 (=> fIdsRole) ) or Qvw.ID IN (30,33 (=> fIdsQvw))
"
I want to write this query with the parameters but I don't know to do it:
SELECT %.ID,Name FROM %
left join %
on %.Dest= %.ID
left join %
on %.Dest= %.ID
%.Source IN (?) or %.Source IN (?) or %.ID IN (?), not with the values
end;Thanks corchi
how to insert a trigger from delphi using your classes
for one table I have three or four tables of relationships,
each table is related to the tables of the user roles and groups
Why did you decide to keep the record of relationships and set the value to 0 rather than deleting the record, remain a lot of unnecessary records of relationships
I have written
function TSQLRestServer.AfterDeleteForceCoherency(Table: TSQLRecordClass;
aID: integer): boolean;
var T, Where: integer;
RecRef: TRecordReference;
begin
result := true; // success if no property found
Where := 0; // make compiler happy
RecRef := RecordReference(Model,Table,aID);
if RecRef<>0 then
for T := 0 to high(Model.RecordReferences) do
with Model.RecordReferences[T] do begin
case FieldType of
sftRecord: // TRecordReference published field
Where := RecRef;
sftID: // TSQLRecord published field
if FieldRecordClass=Table then
Where := aID else
continue;
else continue;
end;
// set Field=0 where Field references aID
// UpdateField(Model.Tables[TableIndex],Where,FieldName^,0,False);
Delete(Model.Tables[TableIndex],Where);
end;
end;There is a "procedure/function" that erases all the relationships are no longer valid?
How to delete a record in one table and automatically to delete all the relationships of same record?
Thanks corchi
I imagined it, but i have one table and more relations and anywhere i delete the record i must to remeber to delete all relations connected to the record.
You know a better way to delete a record and all relationships without having to cycle all the records one by one?
thanks
please help? how to use manydelete in a batch
I wanted to replace
1)ADatabase.Delete (TSQLField, FIDS [i]); with
2)ADatabase.BatchDelete (FIDS [i]);but I have not figured out how do I delete table relationships TSQLField with TSQLQvw? (AQvw.Fields)
I have to do a cycle and delete one at a time?
if ADatabase.TransactionBegin(TSQLField) then
begin
ADatabase.BatchStart(TSQLField);
for I := 0 to Length(fIds) - 1 do
begin
if not (Progress.fCancel) then
begin
// ADatabase.Delete(TSQLField,fIds[i]);
ADatabase.BatchDelete(fIds[i]);
AQvw.Fields.ManyDelete(ADatabase, AQvw.ID, fIds[i]);
Progress.Position := i;
end
else
begin
ADatabase.BatchAbort;
ADatabase.RollBack;
exit;
end;
end;
ADatabase.BatchSend(Results);
ADatabase.Commit;
end;Thanks corchi
You're right for the example above is fast,
but the below example becomes slower .
In the following example, I have to filter "TSQLFile" for users, roles, and groups.
It is very heavy to run every time that i add a new record.
class function TSQLQvw.LoadQvwsForUser(ClientDB: TSQLRestClientUri;const AUser: TSQLUser;Onlypublished:Boolean=false ):TSQLQvw;
var
fIds,fIds2,fIds3,fIds4,fIds5: TIntegerDynArray;
ARole: TSQLRole;
AGruppo :TSQLGruppo;
i:Integer;
fIdsIndexCount: integer;
function checkPublished(ID:Integer):boolean;
var
AQvw:TSQLQvw;
begin
result := false;
try
AQvw := TSQLQvw.Create;
if ClientDB.Retrieve(ID,AQvw) then
result := AQvw.Owner<>AUser.Name;
finally
AQvw.Free;
end;
end;
begin
result := nil;
fIdsIndexCount := 0;
AUser.File.DestGet(ClientDB, AUser.ID, fIds);
// for I := 0 to Length(fIds) - 1 do
// AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
CopyAndSortInteger(Pointer(fIds),Length(fIds),fIds4);
AUser.Groups.FillMany(ClientDB, AUser.ID);
while AUser.Groups.FillOne do
begin
if AUser.Groups.Dest <> nil then
try
AGruppo:= TSQLGruppo.Create(ClientDB, integer(AUser.Groups.Dest));
AGruppo.File.DestGet(ClientDB, AGruppo.ID, fIds);
fIdsIndexCount := Length(fIds4);
for I := 0 to Length(fIds) - 1 do
AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
AGruppo.Roles.FillMany(ClientDB, AGruppo.ID);
while AGruppo.Roles.FillOne do
begin
if AGruppo.Roles.Dest <> nil then
try
ARole:= TSQLRole.Create(ClientDB, integer(AGruppo.Roles.Dest));
ARole.File.DestGet(ClientDB, ARole.ID, fIds);
fIdsIndexCount := Length(fIds4);
for I := 0 to Length(fIds) - 1 do
AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
finally
FreeAndNil(ARole);
end;
end;
finally
FreeAndNil(AGruppo);
end;
end;
AUser.Roles.FillMany(ClientDB, AUser.ID);
while AUser.Roles.FillOne do
begin
if AUser.Roles.Dest <> nil then
try
ARole:= TSQLRole.Create(ClientDB, integer(AUser.Roles.Dest));
ARole.File.DestGet(ClientDB, ARole.ID, fIds);
fIdsIndexCount := Length(fIds4);
for I := 0 to Length(fIds) - 1 do
AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
finally
FreeAndNil(ARole);
end;
end;
if Onlypublished then
begin
for I := Length(fIds4)-1 downto 0 do
begin
if not checkPublished(fIds4[i]) then
begin
DeleteInteger(fIds4,i);
end;
end;
end;
if Length(fIds4)>0 then
begin
result := TSQLQvw.CreateAndFillPrepare(ClientDB, fIds4);
end
else
result := TSQLQvw.CreateAndFillPrepare(ClientDB,'Owner = '''+ AUser.Name+'''')
end;You're right for the example above is fast,
but the below example becomes slower .
In the following example, I have to filter "TSQLFile" for users, roles, and groups.
It is very heavy to run every time that i add a new record.
class function TSQLQvw.LoadQvwsForUser(ClientDB: TSQLRestClientUri;const AUser: TSQLUser;Onlypublished:Boolean=false ):TSQLQvw;
var
fIds,fIds2,fIds3,fIds4,fIds5: TIntegerDynArray;
ARole: TSQLRole;
AGruppo :TSQLGruppo;
i:Integer;
fIdsIndexCount: integer;
function checkPublished(ID:Integer):boolean;
var
AQvw:TSQLQvw;
begin
result := false;
try
AQvw := TSQLQvw.Create;
if ClientDB.Retrieve(ID,AQvw) then
result := AQvw.Owner<>AUser.Name;
finally
AQvw.Free;
end;
end;
begin
result := nil;
fIdsIndexCount := 0;
AUser.File.DestGet(ClientDB, AUser.ID, fIds);
// for I := 0 to Length(fIds) - 1 do
// AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
CopyAndSortInteger(Pointer(fIds),Length(fIds),fIds4);
AUser.Groups.FillMany(ClientDB, AUser.ID);
while AUser.Groups.FillOne do
begin
if AUser.Groups.Dest <> nil then
try
AGruppo:= TSQLGruppo.Create(ClientDB, integer(AUser.Groups.Dest));
AGruppo.File.DestGet(ClientDB, AGruppo.ID, fIds);
fIdsIndexCount := Length(fIds4);
for I := 0 to Length(fIds) - 1 do
AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
AGruppo.Roles.FillMany(ClientDB, AGruppo.ID);
while AGruppo.Roles.FillOne do
begin
if AGruppo.Roles.Dest <> nil then
try
ARole:= TSQLRole.Create(ClientDB, integer(AGruppo.Roles.Dest));
ARole.File.DestGet(ClientDB, ARole.ID, fIds);
fIdsIndexCount := Length(fIds4);
for I := 0 to Length(fIds) - 1 do
AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
finally
FreeAndNil(ARole);
end;
end;
finally
FreeAndNil(AGruppo);
end;
end;
AUser.Roles.FillMany(ClientDB, AUser.ID);
while AUser.Roles.FillOne do
begin
if AUser.Roles.Dest <> nil then
try
ARole:= TSQLRole.Create(ClientDB, integer(AUser.Roles.Dest));
ARole.File.DestGet(ClientDB, ARole.ID, fIds);
fIdsIndexCount := Length(fIds4);
for I := 0 to Length(fIds) - 1 do
AddSortedInteger(fIds4,fIdsIndexCount,fIds[i]);
finally
FreeAndNil(ARole);
end;
end;
if Onlypublished then
begin
for I := Length(fIds4)-1 downto 0 do
begin
if not checkPublished(fIds4[i]) then
begin
DeleteInteger(fIds4,i);
end;
end;
end;
if Length(fIds4)>0 then
begin
result := TSQLQvw.CreateAndFillPrepare(ClientDB, fIds4);
end
else
result := TSQLQvw.CreateAndFillPrepare(ClientDB,'Owner = '''+ AUser.Name+'''')
end;My code is:
{ TSQLFile }
class function TSQLFile.LoadFilesForQvw(ClientDB: TSQLRestClientUri;const AQvw: TSQLQvw):TSQLFile;
var
fIds: TIntegerDynArray;
begin
result := nil;
AQvw.Files.DestGet(ClientDB, AQvw.ID, fIds);
if Length(fIds)>0 then
begin
result := TSQLFile.CreateAndFillPrepare(ClientDB, fIds);
end
else
result := TSQLFile.CreateAndFillPrepare(ClientDB,'Owner = '''+ AQvw.Name+'''');
end;
......
procedure TFrmToolBarMain.ActFiltersExecute(Sender: TObject);
var
AFile: TSQLFile;
begin
Try
FileDlg := TFileDlg.Create(self) ;
AFile:= TSQLFile.LoadFilesForQvw( currentClient ,currentQvw);
if Assigned(AFile) then
begin
FileDlg.SetTable(currentClient,currentQvw,currentUser,AFile);
FileDlg.ShowModal;
end;
finally
FreeAndNil(FileDlg);
end;
end;
....
procedure TFileDlg.ActAddExecute(Sender: TObject);
var
aRec: TSQLFile;
newID:Integer;
refreshed:Boolean;
FileDS : TFileDatasource;
begin
inherited;
aRec:= TSQLFile.Create;
try
aRec.Owner := AQvw.Name;
aRec.Created := Iso8601Now;
aRec.Modified := aRec.Created;
newID:= ADatabase.Add(aRec,true);
aRec.Name := format('File%d', [newID]);
AQvw.Files.ManyAdd(ADatabase,AQvw.ID,newID,true);
Edit(aRec,'Add',false);
finally
FreeAndNil(aRec);
end;
//Here I am forced to run "TSQLFile.CreateAndFillPrepare (ClientDB, FIDS)," otherwise I do not see the new "ID" (inserted record)
try
tb.BeginUpdate;
fRec:= TSQLFile.LoadFilesForQvw( currentClient ,currentQvw);
FileDS := TFileDatasource.Create(tb, ADatabase,fRec);
tb.DataController.CustomDataSource := FileDS;
finally
tb.EndUpdate;
end;
end;Hello time ago I asked you about fillprepare and FillRow, see link http://synopse.info/forum/viewtopic.php?id=188.
I eventually used "TSQLFile.CreateAndFillPrepare (ClientDB, FIDS)," to create a "resultset", I used "Client.Update (Rec)" and "Client.UpdateFromServer ([Table], Refreshed);" to update a records on the server and display the result in a quantumgrid and up to here everything is working.
Now I have the problem that if I add a record to the table "TSQLFile" I'm forced to run again "TSQLFile.CreateAndFillPrepare (ClientDB, FIDS);" to view data in the grid, then I ask you can I not run a ResultSet.Add and then ResultSet.Refresh.
I ask this because FLDS is a "FIDS: TIntegerDynArray," is the result of a non-functioning, which is cumbersome if you have to run every Add, Remove the recordset
Thanks, sorry for my english.
Hi,
if i execute the connection with the server that is not started, i have a exception.
procedure LoadClientDatabase(var ClientDB: TSQLRestClientDB; ServerName: string; Port: Integer);
begin
try
Model := GetDatabaseModel('root');
ClientDB := TSQLRestClientDB(TSQLite3HttpClient.Create(ServerName, IntToStr(Port), Model));
except
//on E: Exception do
// handle initialization error here
end;
end;Can I avoid the exception and perform a test to see if the server is reachable or started?
thanks corchi
ok thanks,
I have read and produced the following example that sends a filename to the server which returns the string read xml file in the directory server:
unit FileTables
....
function TServiceServer.DataAsXML(aRecord: TSQLRecord;
aParameters: PUTF8Char; const aSentData: RawUTF8; out aResp, aHead: RawUTF8): Integer;
var //aData: TSQLRawBlob;
sfilename:RawUTF8;
XmlDoc: TNativeXml;
aData: RawUTF8 ;
begin
writeln('Start DataAsXML');
if not UrlDecodeNeedParameters(aParameters,'FILENAME') then begin
result := 404; // invalid Request
writeln('invalid Request');
exit;
end;
while aParameters<>nil do begin
UrlDecodeValue (aParameters,'FILENAME=',sfilename,@aParameters);
end;
writeln(format('filename: %s',[sfilename]));
if FileExists(sfilename) then
begin
writeln(format('Exist file: %s',[sfilename]));
try
XmlDoc := TNativeXml.Create(nil);
XmlDoc.LoadFromFile(sfilename);
if (XmlDoc <> nil) Then
begin
aData := XmlDoc.WriteToLocalString;
end;
finally
XmlDoc.Free;
end;
end
else
begin
result := 404; // invalid Request
exit; // we need a valid record and its ID
end;
aResp := JSONEncodeResult([aData]);
//aResp := JSONEncodeResult([SynCommons.BinToHex(aData)]);
// idem: aResp := JSONEncode(['result',BinToHex(aRecord.fData)],TempMemoryStream);
result := 200; // success
end;
..............................end FileTables
........ Client procedure
Var
sfilename:String;
XmlDoc: TNativeXml;
aData: RawUTF8;
begin
..
aData := ADatabaseServer.CallBackGetResult('DataAsXML',['filename',StringtoUTF8(sfilename)]);
if Length(aData)>0 then
begin
sfilename := nome;
sfilename := format('%s%s.xml',[GetTempDir, ReplaceStr(sfilename,'\','_')]) ;
XmlDoc.ReadFromString(UTF8ToString(aData));
XmlDoc.SaveToFile(sfilename);
end;
...
end;but now I want to send the xml string to the server and the server would that save the document with a specific name
I wrote the following example using "CallBackPut" but I can not send the parameters type "filename" to "XMLAsData",
and I can not read the parameters returned by procedure "aResp: JSONEncodeResult = ([sFileName]);"
unit FileTables
....
function TServiceServer.XMLAsData(aRecord: TSQLRecord;
aParameters: PUTF8Char; const aSentData: RawUTF8; out aResp, aHead: RawUTF8): Integer;
var //aData: TSQLRawBlob;
sfilename:RawUTF8;
XmlDoc: TNativeXml;
aData: RawUTF8 ;
Node: TXmlNode;
begin
writeln('Start XMLAsData');
// if not UrlDecodeNeedParameters(aParameters,'FILENAME') then begin
// result := 404; // invalid Request
// writeln('invalid Request');
// exit;
// end;
// while aParameters<>nil do begin
// UrlDecodeValue (aParameters,'FILENAME=',sfilename,@aParameters);
// end;
// writeln(format('filename: %s',[sfilename]));
if length(aSentData)>0 then
begin
// writeln(format('Exist data: %s',[aSentData]));
try
XmlDoc := TNativeXml.Create(nil);
XmlDoc.ReadFromString(UTF8ToString(aSentData));
sfilename := format('%s%s.xml',[GetTempDir, ReplaceStr(sfilename,'\','_')]) ;
XmlDoc.SaveToFile(sfilename);
finally
XmlDoc.Free;
end;
end
else
begin
result := 404; // invalid Request
exit; // we need a valid record and its ID
end;
aResp := JSONEncodeResult([sfilename]);
writeln(format('Exist data: %s',[aResp]));
// idem: aResp := JSONEncode(['result',BinToHex(aRecord.fData)],TempMemoryStream);
result := 200; // success
end;
..............................end FileTables
........ Client procedure
Var
sfilename:String;
XmlDoc: TNativeXml;
aData: RawUTF8;
aResponse: RawUTF8;
begin
...
aData := " Here insert the xml string !!!!!!!!"
ADatabaseServer.CallBackPut('XMLAsData',aData,aResponse);
sfilename := UTF8ToString(aResponse); "the value returned is always empty !!!!!!!!"
..
end;can you help me ?
thanks corchi
I only found this documentation,
http://synopse.info/forum/viewtopic.php?id=256
where I can entice the right one?
thanks corchi
I can run a server function from a client station if I used TSQLRestServerDB TSQLite3HttpClient server side and client-side
I need to send me an xml file from the server (I read files from a directory server)
thanks corchi
ok thanks
Today I downloaded the "6f2a76894f" Synops of, but completing an error occurs in file "SQLite3UIEdit"at line
aCaption: = CaptionName (OnCaptionName, @ P ^. Name);
I saw that you have modified the file "SQLite3i18n" and you have replaced
text: = TranslateOne (CompName, ppi ^. Name);
with
text: = TranslateOne (CompName, ppi ^. ShortName);
Thank corchi
I do not understand, AFAIK is a directive compiler?
I found only these two lines of comments that refer to AFAIK
1) // - it's still fast, faster than any DB AFAIK, around 500 updates
...
2){ Below we just ignore the value of next string token.
We can do this -- because PasDoc (at least for now)
does not recursively parse units on "uses" clause.
So we are not interested in the value of
given string (which should be a file-name (usually relative,
but absolute is also allowed AFAIK) with given unit.)
odd because I created a variable called "$ (Synops) " with the path of the source of "Synops OpenSource" and in fact if I create a simple project it works.
The component is very simple and is what I set out below.
$(Synopse) = c:\.....\Synopse OpenSource
$(sqlite3obj); where i put sqlite3.obj and sqlite3fts3.obj
$(Synopse);
$(Synopse)\SQLite3;
package SQliteComponent;
{$R *.res}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
{$DEBUGINFO ON}
{$EXTENDEDSYNTAX ON}
{$IMPORTEDDATA ON}
{$IOCHECKS ON}
{$LOCALSYMBOLS ON}
{$LONGSTRINGS ON}
{$OPENSTRINGS ON}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
{$REFERENCEINFO ON}
{$SAFEDIVIDE OFF}
{$STACKFRAMES OFF}
{$TYPEDADDRESS OFF}
{$VARSTRINGCHECKS ON}
{$WRITEABLECONST OFF}
{$MINENUMSIZE 1}
{$IMAGEBASE $400000}
{$IMPLICITBUILD ON}
{$DEFINE USETMSPACK}
requires
rtl;
contains
SQLite3UI in '..\Synopse OpenSource\SQLite3\SQLite3UI.pas';
end.
//is a simple package that uses your unit
unit SQLite3UI;
....
procedure Register;
begin
RegisterComponents('Synopse',[TSynLabeledEdit]);
end;Error: impossible to find file "C:\......\SQLite3i18n.pas"
Why
I created a unit called "FileTables" that uses classes and SQLite3 SynCommons but when compiling I get errors "can not find the file SQLite3.pas"even though I entered the path in the Delphi library.
Using the same unit from a project the error does not occur.
What should I add to the component you do not need to add to a project?
unit FileTables;
interface
uses
Windows,
SysUtils,
SynCommons,
SQLite3,
SQLite3Commons,
SQLite3HttpClient,SQLite3HttpServer;
...Ok I put this new procedure in the base form, and when I writing into a textbox I will write : SetValue('Fieldname','value');
procedure TFrmEditBase.SetValue(FieldName:String; Value: String);
var
FieldIndex:Integer;
C: TWinControl;
CLE: TLabeledEdit absolute C;
U: RawUTF8;
P: PPropInfo;
Props: TSQLRecordProperties;
begin
Props := fRec.RecordProps;
FieldIndex := Props.FieldIndexFromRawUTF8(FieldName);
if cardinal(Props.FieldIndexFromRawUTF8(FieldName))<cardinal(length(fFieldComponents)) then
begin
C := fFieldComponents[FieldIndex];
C.SetFocus;
if C.InheritsFrom(TLabeledEdit) then begin
begin
CLE.Text := Value;
U := S2U(CLE.Text);
P := Props.Fields[FieldIndex];
P^.SetValue(fRec,pointer(U)); // do conversion for every string type
end;
end
end;
end;Thanks
Hello,
I have created a form inheriting class (TRTTIForm), copiando quanto c'è scritto nella unit SQLite3UIEdit, I have attached the code below:
unit UFrmEditBase;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, ActnList, StdCtrls, ExtCtrls, AdvPanel,
SQLite3UIEdit,
SynCommons, SynCrypto, SynGdiPlus,
SQLite3Commons,
SQLite3UILogin,
SQLite3UI,
SQLite3i18n,SQLite3ToolBar, AdvGlowButton
;
type
TFrmEditBase = class(TRTTIForm)
ActionList1: TActionList;
ActAdd: TAction;
ActRemove: TAction;
ActSave: TAction;
ActCancel: TAction;
ActClose: TAction;
PopupMenu1: TPopupMenu;
Nuovo1: TMenuItem;
Annulla1: TMenuItem;
Chiudi1: TMenuItem;
Chiudi2: TMenuItem;
Salva1: TMenuItem;
N1: TMenuItem;
N2: TMenuItem;
Scroll: TScrollBox;
BottomPanel: TPanel;
BtnSave: TAdvGlowButton;
BtnCancel: TAdvGlowButton;
procedure FormShow(Sender: TObject);
procedure ActSaveExecute(Sender: TObject);
procedure ActCancelExecute(Sender: TObject);
private
procedure Save(Sender: TObject);
protected
fRec: TSQLRecord;
fClient: TSQLRestClient;
ADatabase: TSQLRestClient;
fOnComponentValidate: TOnComponentValidate;
/// as created by SetRecord()
fFieldComponents: array of TWinControl;
fFieldCaption: array of string;
// avoid Windows Vista and Seven screen refresh bug (at least with Delphi 7)
fReadOnly: boolean;
procedure WMUser(var Msg: TMessage); message WM_USER;
public
/// create the corresponding components on the dialog for editing a Record
// - to be used by OnComponentCreate(nil,nil,EditForm) in order
// to populate the object tree of this Form
// - create field on the window for all published properties of the
// supplied TSQLRecord instance
// - properties which name starts by '_' are not added to the UI window
// - user can customize the component creation by setting the
// OnComponentCreate / OnComponentCreated events
// - the supplied aRecord instance must be available during all the
// dialog window modal apparition on screen
// - by default, all published fields are displayed, but you can specify
// a CSV list in the optional CSVFieldNames parameter
// - editor parameters are taken from the optional Ribbon parameter,
// and its EditFieldHints/EditExpandFieldHints/EditFieldNameWidth properties
// - if Ribbon is nil, FieldHints may contain the hints to be displayed on
// screen (useful if your record is not stored in any TSQLRestClient, but
// only exists in memory); you can set FieldNamesWidth by hand in this case
procedure SetRecord(aClient: TSQLRestClient; aRecord: TSQLRecord;
CSVFieldNames: PUTF8Char=nil; Ribbon: TSQLRibbon=nil;
FieldHints: string=''; FieldNamesWidth: integer=0; aCaption: string='');
/// the associated Record to be edited
property Rec: TSQLRecord read fRec;
/// the associated database Client, used to access remote data
property Client: TSQLRestClient read fClient;
/// event called to check if the content of a field on form is correct
// - is checked when the user press the "Save" Button
// - if returns false, component is focused and window is not closed
property OnComponentValidate: TOnComponentValidate read fOnComponentValidate write fOnComponentValidate;
property ReadOnly: boolean read fReadOnly write fReadOnly;
end;
var
FrmEditBase: TFrmEditBase;
function Cypher(const Title: string; var Content: TSQLRawBlob; Encrypt: boolean): boolean;
implementation
{$R *.dfm}
resourcestring
sEdit = 'Edit';
sVerb = '%s %s';
sInvalidFieldN = 'Invalid "%s" Field';
procedure TFrmEditBase.SetRecord(aClient: TSQLRestClient;
aRecord: TSQLRecord; CSVFieldNames: PUTF8Char=nil; Ribbon: TSQLRibbon=nil;
FieldHints: string=''; FieldNamesWidth: integer=0; aCaption: string='');
var i,j, aID, Y, aHeight, aWidth, CW: integer;
RibbonParams: PSQLRibbonTabParameters;
ExpandFieldHints: boolean;
E: PEnumType;
EP: PShortString;
Group: TGroupBox;
C: TWinControl;
CLE: TLabeledEdit absolute C;
CNE: TSynLabeledEdit absolute C;
CC: TCheckbox absolute C;
CB: TCombobox absolute C;
aClassType: TSQLRecordClass;
Sets: cardinal;
IDClass: TSQLRecordClass;
aHint: string;
aName: RawUTF8;
FieldNameToHideCSV: PUTF8Char;
P: PPropInfo;
PHint: PChar; // map FieldHints
begin
if (self=nil) or (aRecord=nil) then
exit; // avoid GPF
RibbonParams := Ribbon.GetParameter(aRecord.RecordClass);
if RibbonParams=nil then begin
ExpandFieldHints := (FieldHints<>'');
FieldNameToHideCSV := nil;
if FieldNamesWidth=0 then
FieldNamesWidth := 200; // default value
end else
with RibbonParams^ do begin
FieldNamesWidth := EditFieldNameWidth;
if FieldNamesWidth=0 then
FieldNamesWidth := 200; // default value
if EditFieldHints<>nil then
FieldHints := LoadResString(EditFieldHints);
ExpandFieldHints := EditExpandFieldHints;
FieldNameToHideCSV := pointer(EditFieldNameToHideCSV);
end;
fRec := aRecord;
fClient := aClient;
CW := Scroll.ClientWidth;
aName := aClient.MainFieldValue(aRecord.RecordClass,aRecord.ID,true);
if aCaption='' then begin
if Caption='' then
aCaption := sEdit else
aCaption := Caption;
aCaption := format(sVerb,[aCaption,aRecord.CaptionName]);
if aName<>'' then
aCaption := aCaption+' - '+U2S(aName); // add current record name
end;
Caption := ' '+aCaption;
with TStaticText.Create(Scroll) do begin
Parent := Scroll;
Alignment := taCenter;
Font.Style := [fsBold];
Font.Size := 12;
Font.Color := clTeal;
Caption := aCaption;
SetBounds(8,16,CW-48,Height);
Y := Top+Height+16;
end;
with TBevel.Create(Scroll) do begin
Parent := Scroll;
SetBounds(8,Y-12,CW-32,4);
Shape := bsTopLine;
end;
aClassType := PPointer(aRecord)^;
dec(CW,FieldNamesWidth+32);
PHint := pointer(FieldHints);
with aClassType.RecordProps do begin
SetLength(fFieldComponents,length(Fields));
SetLength(fFieldCaption,length(Fields));
for i := 0 to High(Fields) do begin
aHint := GetNextItemString(PHint,'|'); // ALL fields are listed: do it now
P := Fields[i];
aName := FieldsName[i];
if ((FieldType[i] in [ // must match case "FieldType[i] of" below
sftRecord, sftTimeLog, sftCurrency, sftDateTime, sftFloat, sftBlob]) and
not Assigned(OnComponentCreate)) or
((FieldNameToHideCSV<>nil) and
(FindCSVIndex(FieldNameToHideCSV,aName,',',false)>=0)) or
((CSVFieldNames<>nil) and
(FindCSVIndex(CSVFieldNames,aName,',',false)<0)) then
continue; // display properties listed in optional CSVFieldNames parameter
aCaption := CaptionName(OnCaptionName,@P^.Name);
fFieldCaption[i] := aCaption;
if (aHint<>'') and ExpandFieldHints then
with TLabel.Create(Scroll) do begin // show hint above field
Parent := Scroll;
Font.Color := clNavy;
Font.Size := 8;
AutoSize := True;
WordWrap := true;
SetBounds(FieldNamesWidth,Y+8,CW-32,24);
Caption:= aHint;
inc(Y,Height+10);
aHint := ''; // mark hint displayed on window -> no popup needed
end;
aHeight := 24;
// try custom component creation
if not Assigned(OnComponentCreate) then
C := nil else
C := OnComponentCreate(aRecord,P,Scroll);
if C=nil then begin
// default creation from RTTI, if not handled by OnComponentCreate()
case FieldType[i] of
sftRecord, sftTimeLog, sftCurrency, sftDateTime, sftFloat, sftBlob:
; // not implemented yet (not needed yet, to be honest)
sftInteger:
// integer field is handled by a TSynLabeledEdit component
if P^.PropType^^.Kind=tkInteger then begin // tkInt64 not handled yet
CNE := TSynLabeledEdit.Create(Scroll);
CNE.Value := P^.GetOrdValue(aRecord);
CNE.RaiseExceptionOnError := true; // force show errors on screen
end;
sftEnumerate: begin
// enumeration is handled by a TComboBox with all possible values
E := P^.PropType^^.EnumBaseType;
CB := TComboBox.Create(Scroll);
CB.Parent := Scroll; // need parent now for CB.Items access
CB.Style := csDropDownList;
EP := @E^.NameList;
for j := 0 to E^.MaxValue do begin
CB.Items.Add(CaptionName(OnCaptionName,EP));
inc(PtrInt(EP),ord(EP^[0])+1); // next enumeration item
end;
CB.ItemIndex := P^.GetOrdValue(aRecord);
end;
sftID:
if aClient<>nil then begin
// ID field (TSQLRecord descendant) is handled by a TComboBox component
// with all possible values of the corresponding TSQLRecord descendant
IDClass := TSQLRecordClass(P^.PropType^^.ClassType^.ClassType);
CB := TComboBox.Create(Scroll);
CB.Parent := Scroll; // need parent now for CB.Items access
CB.Style := csDropDownList;
aID := P^.GetOrdValue(aRecord);
with IDClass.RecordProps do
if MainField[true]>=0 then begin
aClient.OneFieldValues(IDClass,FieldsName[MainField[true]],'',CB.Items,@aID);
CB.ItemIndex := aID; // @aID now contains the found index of aID
end;
end;
sftSet: begin
// enumeration set if handled by a TGroupBox component contaning one
// TCheckBox for each enumeration value
Group := TGroupBox.Create(Scroll); // add left-sided label
Group.Parent := Scroll;
Group.Font.Style := [fsBold];
Group.Caption := ' '+aCaption+' ';
Group.Tag := i+1; // for BtnSaveClick() event
if Assigned(OnComponentCreated) then // allow component customization
OnComponentCreated(aRecord,P,Group); // e.g. set Group.Enabled := false
Sets := P^.GetOrdValue(aRecord);
E := P^.PropType^^.SetEnumType;
aWidth := 200;
EP := @E^.NameList;
for j := 0 to E^.MaxValue do begin
if EP^[0]>#25 then begin
aWidth := 250; // wider group box for large enumeration caption
break;
end;
inc(PtrInt(EP),ord(EP^[0])+1); // next enumeration item
end;
Group.SetBounds(FieldNamesWidth,Y+4,aWidth,40+20*E.MaxValue);
dec(aWidth,20);
EP := @E^.NameList;
for j := 0 to E^.MaxValue do
with TCheckBox.Create(Scroll) do begin // add set checkboxes
Parent := Group;
Font.Style := [];
Caption := CaptionName(OnCaptionName,EP);
inc(PtrInt(EP),ord(EP^[0])+1); // next enumeration item
SetBounds(16,16+20*j,aWidth,20);
if aHint<>'' then begin
Hint := aHint;
ShowHint := True;
end;
Checked := GetBit(Sets,j);
Enabled := Group.Enabled;
Tag := i+1+(j+1) shl 8; // for BtnSaveClick() event
end;
inc(Y,Group.Height+12);
continue;
end;
sftBoolean: begin
// boolean is handled by a TCheckBox component
CC := TCheckBox.Create(Scroll);
CC.Parent := Scroll; // initialize font
CC.Font.Style := [fsBold];
CC.Checked := boolean(P^.GetOrdValue(aRecord));
CC.Caption := aCaption;
end;
sftUTF8Text, sftAnsiText: begin
// text field is handled by a TLabeledEdit component
CLE := TLabeledEdit.Create(Scroll);
{$ifdef UNICODE}
if P^.PropType^^.Kind=tkUString then
CLE.Text := P^.GetUnicodeStrValue(aRecord) else
{$endif}
CLE.Text := U2S(P^.GetValue(aRecord,False)); // convert in GetValue()
CLE.Name := P^.Name;
end;
end;
end;
if (C<>nil) and (C<>self) and (C<>Scroll) then begin
// we reached here if a component was added on screen for this field
C.Parent := Scroll;
C.Tag := i+1; // for BtnSaveClick() event
if aHint<>'' then begin
C.Hint := aHint; // show hint text as popup
C.ShowHint := true;
end;
if Assigned(OnComponentCreated) then // allow component customization
OnComponentCreated(aRecord,P,C); // e.g. set C.Enabled := false
if not C.InheritsFrom(TCheckBox) then
if C.InheritsFrom(TLabeledEdit) then begin
CLE.EditLabel.Font.Style := [fsBold];
CLE.EditLabel.Caption := aCaption;
CLE.LabelPosition := lpLeft;
end else
with TLabel.Create(Scroll) do begin // add label left-sided to the field
Parent := Scroll;
Font.Style := [fsBold];
Caption := aCaption;
SetBounds(8,Y+4,FieldNamesWidth-12,Height);
Alignment := taRightJustify;
if not C.Enabled then
Enabled := false;
end;
if C.InheritsFrom(TCheckBox) then // trick to avoid black around box
CC.SetBounds(FieldNamesWidth,Y,CW,CC.Height) else
C.SetBounds(FieldNamesWidth,Y,200,22);
fFieldComponents[i] := C;
inc(Y,aHeight);
end;
end;
end;
// draw a line at the bottom of the scroll box
with TBevel.Create(Scroll) do begin
Parent := Scroll;
SetBounds(8,Y+8,CW+FieldNamesWidth,16);
Shape := bsTopLine;
end;
Inc(Y,BottomPanel.Height+32);
// resize height to fit the fields (avoid bottom gap)
if ClientHeight>Y then
ClientHeight := Y;
end;
procedure TFrmEditBase.ActCancelExecute(Sender: TObject);
begin
modalresult := mrCancel;
end;
procedure TFrmEditBase.ActSaveExecute(Sender: TObject);
begin
Save(Sender);
end;
procedure TFrmEditBase.FormShow(Sender: TObject);
begin
Application.ProcessMessages;
Screen.Cursor := crHourGlass;
try
if Assigned(OnComponentCreate) then
OnComponentCreate(nil,nil,self); // will call AddEditors() to create nodes
SetStyle(self);
finally
Screen.Cursor := crDefault;
end;
PostMessage(Handle,WM_USER,0,0); // avoid Vista and Seven screen refresh bug
end;
procedure TFrmEditBase.WMUser(var Msg: TMessage);
var i: integer;
begin
for i := 0 to Scroll.ControlCount-1 do
Scroll.Controls[i].Repaint;
end;
procedure TFrmEditBase.Save(Sender: TObject);
var j, FieldIndex, SetIndex, aID: integer;
Value: set of 0..31;
U: RawUTF8;
C: TWinControl;
CLE: TLabeledEdit absolute C;
CNE: TSynLabeledEdit absolute C;
CC: TCheckbox absolute C;
CB: TCombobox absolute C;
CG: TGroupBox absolute C;
Props: TSQLRecordProperties;
P: PPropInfo;
ModifiedFields: TSQLFieldBits;
ErrMsg: string;
begin
if Rec=nil then
exit;
Props := Rec.RecordProps;
Int64(ModifiedFields) := 0;
for FieldIndex := 0 to high(fFieldComponents) do begin
C := fFieldComponents[FieldIndex];
if (C=nil) or not C.Enabled then
continue; // disabled components didn't modify their value
assert(FieldIndex=(C.Tag and 255)-1);
P := Props.Fields[FieldIndex];
if Assigned(OnComponentValidate) and not OnComponentValidate(C,P) then begin
// invalid field content -> abort saving
C.SetFocus;
exit;
end;
if C.InheritsFrom(TSynLabeledEdit) then
try
P^.SetOrdValue(Rec,CNE.Value); // call CNE.GetValue for range checking
Include(ModifiedFields,FieldIndex);
except
on E: ESynLabeledEdit do begin // trigerred by CNE.GetValue
CNE.SetFocus;
ShowMessage(CNE.EditLabel.Caption+':'#13+E.Message,true);
exit;
end;
end else
if C.InheritsFrom(TLabeledEdit) then begin
U := S2U(CLE.Text);
P^.SetValue(Rec,pointer(U)); // do conversion for every string type
Include(ModifiedFields,FieldIndex);
end else
if C.InheritsFrom(TGroupBox) then begin
for j := 0 to CG.ControlCount-1 do
if CG.Controls[j].InheritsFrom(TCheckBox) then
with TCheckBox(CG.Controls[j]) do begin
SetIndex := (Tag shr 8)-1;
if cardinal(SetIndex)<32 then begin
integer(Value) := P^.GetOrdValue(Rec);
if Checked then
include(Value,SetIndex) else
exclude(Value,SetIndex);
P^.SetOrdValue(Rec,integer(Value));
Include(ModifiedFields,FieldIndex);
end;
end;
end else
if C.InheritsFrom(TCheckBox) then begin
if CC.Tag<255 then begin
P^.SetOrdValue(Rec,integer(CC.Checked));
Include(ModifiedFields,FieldIndex);
end;
end else
if C.InheritsFrom(TComboBox) then begin
SetIndex := CB.ItemIndex;
case P^.PropType^^.SQLFieldType of
sftEnumerate:
if SetIndex>=0 then begin
P^.SetOrdValue(Rec,SetIndex);
Include(ModifiedFields,FieldIndex);
end;
sftID: begin
if SetIndex<0 then
aID := 0 else
aID := PtrInt(CB.Items.Objects[SetIndex]);
P^.SetOrdValue(Rec,aID);
Include(ModifiedFields,FieldIndex);
end;
end;
end;
end;
// perform all registered filtering
Rec.Filter(ModifiedFields);
// perform content validation
FieldIndex := -1;
ErrMsg := Rec.Validate(Client,ModifiedFields,@FieldIndex);
if ErrMsg<>'' then begin
// invalid field content -> show message, focus component and abort saving
if cardinal(FieldIndex)<cardinal(length(fFieldComponents)) then begin
C := fFieldComponents[FieldIndex];
C.SetFocus;
Application.ProcessMessages;
ShowMessage(ErrMsg,format(sInvalidFieldN,[fFieldCaption[FieldIndex]]),true);
end else
ShowMessage(ErrMsg,format(sInvalidFieldN,['?']),true);
end else
begin
fClient.update(Rec);
// close window on success
ModalResult := mrOk;
end;
end;
function Cypher(const Title: string; var Content: TSQLRawBlob; Encrypt: boolean): boolean;
resourcestring
sEnterPassword = 'Enter password for this record:';
var AES: TAESFull;
SHA: TSHA256Digest;
PassWord: string;
Len: integer;
begin
result := Content='';
if result then
exit;
if not TLoginForm.PassWord(Title,sEnterPassword,PassWord) then
exit;
SHA256Weak(S2U(PassWord), SHA);
try
Len := AES.EncodeDecode(SHA,256,length(Content),Encrypt,nil,nil,Pointer(Content),nil);
if Len<0 then
exit;
SetString(Content,PAnsiChar(AES.outStreamCreated.Memory),Len);
result := true;
finally
AES.OutStreamCreated.Free;
end;
end;
end.and it all works, the components are created "TLabeledEdit" etc. .. vost as in example, but when I refer to an object created at runtime what to write?
Let me explain with an example:
TSQLUser = class(TSQLFile)
private
fRoles: TSQLUserRoles;
fLogin, fPassword: RawUTF8;
fName : RawUTF8;
fSubName: RawUTF8;
....
function TFrmElencoUser.Edit(Rec: TSQLFile; const Title: string; ReadOnly: boolean): boolean;
var
refreshed:Boolean;
begin
fRec := TSQLUser(Rec);
try
FrmEditUser := TFrmEditUser.Create(Self); // TFrmEditUser = class(TFrmEditBase)
FrmEditUser.Caption := ' '+Title;
FrmEditUser.ReadOnly := ReadOnly;
FrmEditUser.SetRec(ADatabase,fRec);
....
end;
function TFrmEditUser.SetRec(aClient: TSQLRestClient;const Value: TSQLUser): boolean;
begin
result := false;
fRec := Value;
ADatabase := aClient;
SetRecord(ADatabase,Value);
.....
//now I want to change the value of a property by code
procedure TFrmEditUser.changeSubName(value:String);
begin
fRec.SubName := value; //now if I run the form's save the value of the property is replaced with the same property attached to TlabelEdit.text
end;so I decided to write directly into TlabelEdit.text, but I do not know how to find the one attached to the property subname.
so I added the line "CLE.Name: = P ^. Name," to name the object created at runtime
sftUTF8Text, sftAnsiText: begin
// text field is handled by a TLabeledEdit component
CLE := TLabeledEdit.Create(Scroll);
{$ifdef UNICODE}
if P^.PropType^^.Kind=tkUString then
CLE.Text := P^.GetUnicodeStrValue(aRecord) else
{$endif}
CLE.Text := U2S(P^.GetValue(aRecord,False)); // convert in GetValue()
CLE.Name := P^.Name; // I added this line
end;and I corrected the procedure "changeSubName" as follows:
procedure TFrmEditUser.changeSubName(value:String);
begin
fRec.SubName := value;
for i := 0 to Self.ControlCount-1 do
begin
if self.Controls[i] is TScrollBox then
begin
if self.Controls[i].findcomponent('SubName') is TLabeledEdit then
TLabeledEdit( self.Controls[i].findcomponent('SubName')).Text := fRec.SubName;
break;
end;
end;The question is: is there some other way to achieve the same result?
Thanks
There are examples with TSQLTableJSON?
Thanks
I'm sorry but maybe I was not clear, I have already run the above command
"TSQLField.CreateAndFillPrepar (ADatabase, FIDS), and now I just wanted to do a search on the list already exists, but if I understand it is not possible, I have to scroll all the records with "Fillone" to compare data.
var
fIds: TIntegerDynArray;
begin
result := nil;
AQvw.Fields.DestGet(ADatabase, AQvw.ID, fIds);
if Length(fIds)>0 then
begin
result := TSQLField.CreateAndFillPrepare(ADatabase, fIds);I come to the point:
I am seeing a list of codes in a grid and I wanted to do a lookup table with TSQLField (daughter of TSQLQvw), also in the grid to display the description for.
I have created 2 classes and the relationship "one to many" between the two classes.
TSQLQvwFields = class(TSQLRecordMany)
private
fSource: TSQLQvw;
fDest: TSQLField;
published
property Source: TSQLQvw read fSource;
property Dest: TSQLField read fDest;
end;
TSQLQvw = class(TSQLFile)
private
..
fFields: TSQLQvwFields;
end;
TSQLField = class(TSQLFile)
private
fOwner: RawUTF8;
fEnabled: boolean;
public
published
property Name;
property Created;
property Modified;
property KeyWords;
property SignatureTime;
property Signature;
property Owner: RawUTF8 read fOwner write fOwner;
property Enabled: boolean read fEnabled write fEnabled;
end;Then I have created a function that exposes only the child records in the table SQLQvw
{ TSQLField }
function LoadFieldForQvw(ADatabase: TSQLRestClient;const AQvw: TSQLQvw):TSQLField;
var
fIds: TIntegerDynArray;
begin
result := nil;
AQvw.Fields.DestGet(ADatabase, AQvw.ID, fIds);
if Length(fIds)>0 then
begin
result := TSQLField.CreateAndFillPrepare(ADatabase, fIds);
end;
end;now I need to do a search in the range of data that I have created, what should I write?
//Example
procedure TFrmEditFileQvw.ActFieldsExecute(Sender: TObject);
var
AField: TSQLField;
List:TStringlist;
i:Integer;
begin
try
List:=TStringlist.Create;
List.Add('A001');
List.Add('B001');
AField:= LoadFieldForQvw( currentDatabase ,Rec);
if Assigned(AField) then
begin
for i := 0 to List.Count -1 do
if AField = List[i] then // here what should I write??????????
Showmessage('I found it:...');
end;
finally
FreeAndnil(List);
end;
end;Thanks
If you fill out the code for version 8455306490772f68 gives you the error the line
TSynToolBar = class (TAdvToolBar), because the ";" should not be there.
In addition, verifcano other errors trying to compile with the directive "USETMSPACK"
let me know if you by mistake
/// a TMS toolbar
TSynToolBar = class(TAdvToolBar);
public
...
Certainly, I have three tables:
1) users
2) groups
3) roles
and three other reports many to many
1) user groups
2) users roles
3) groups roles
The three tables residing in a sqlite file that I put in a server.
So I created a 'client / server application.
The program is used by agents but are not always present in the company so I have to replicate the tables also in their PC with all the reports.
In addition, each agent should contain only information relating to its user, so it must have its user, only groups to which it belongs, and the roles to which it is enabled.
Managing users, groups, and roles, is made by an administrator in the sqlite file on the server, and only when each user connects to the server attempts to synchronize the 6 tables.
the 6 tables are the ones I described above, three more tables with their relations
I thank you in advance for your willingness
excuse me explain.
I have 3 tables in the server and three tables on the client I want to keep in line without having to check if they are different because I always want to delete the three tables of the client and overwrite them with the 3 tables on the server. What should I write?
ok Thanks
I saw that executing the function:
FromUser.Groups.FillMany(AFromDatabase, FromUser.ID);
while FromUser.Groups.FillOne do
begin
if AToDatabase.Retrieve(FromUser.Groups.Dest.ID,AGruppo) then
begin
if AFromDatabase.Retrieve(FromUser.Groups.Dest.ID,FromGruppo) then
begin
if not AGruppo.SameValues(FromGruppo) then
AToDatabase.Update(FromGruppo);
end;
end
else
begin
if AFromDatabase.Retrieve(FromUser.Groups.Dest.ID,FromGruppo) then
AToDatabase.Add(FromGruppo,true);
end;
ToUser.Groups.ManyAdd(AToDatabase,FromUser.Groups.Source.ID,FromUser.Groups.Dest.ID,true);
end;
FromUser.Roles.FillMany(AFromDatabase, FromUser.ID);
while FromUser.Roles.FillOne do
begin
if AToDatabase.Retrieve(FromUser.Roles.Dest.ID,ARole) then
begin
if AFromDatabase.Retrieve(FromUser.Roles.Dest.ID,FromRole) then
begin
if not ARole.SameValues(FromRole) then
AToDatabase.Update(FromRole);
end;
end
else
begin
if AFromDatabase.Retrieve(FromUser.Roles.Dest.ID,FromRole) then
AToDatabase.Add(FromRole,true);
end;
ToUser.Roles.ManyAdd(AToDatabase,FromUser.Roles.Source.ID,FromUser.Roles.Dest.ID,true);
end;
FromUser.Groups.FillMany(AFromDatabase, FromUser.ID);
while FromUser.Groups.FillOne do
begin
if AFromDatabase.Retrieve(FromUser.Groups.Dest.ID,FromGruppo) then
begin
if AToDatabase.Retrieve(FromUser.Groups.Dest.ID,AGruppo) then
begin
FromGruppo.Roles.DestGet(AFromDatabase, FromGruppo.ID, fIds);
for i := 0 to Length(fIds) - 1 do
begin
AGruppo.Roles.ManyAdd(AToDatabase, AGruppo.ID, fIds[i],True);
end;
end;
end;
end;is not maintained in the source ID is created, but again, so I decided to cancallare always the destination table and copy all records ever in the source table, what should I write to perform INSERT and DELETE * FROM table for each record?
Can you help?
Hello I am developing a program to work with databases on a server and a db with the same tables on a client, I perform a merge of the data tables by executing filtering by user, is it possible? What should I write to perform a merge of records between tables?
Thanks
ok Thanks
Deleting a user performing the example "Synops-sqlite-demo" occurs the error: unrecognized token: ""
I added a button where I run the cancellation of the user with the following code:
procedure TForm1.btnDeleteUserClick(Sender: TObject);
begin
Database.Delete(TSQLUser,integer(lbUsers.Items.Objects[lbUsers.ItemIndex]));
end;
debuging I saw that goes wrong when running the following code:
function TSQLRestServerDB.EngineExecuteAll(const aSQL: RawUTF8): boolean;
begin
try
DB.ExecuteAll(aSQL); // Execute all statements (don't use fStatementCache[])
result := true;
except
on E: ESQLException do begin
LogToTextFile('TSQLRestServerDB.EngineExecuteAll Error: '+RawUTF8(E.Message)+#13#10+aSQL);
result := false;
end;
end;
end;
ok thanks
thanks,
Can I download the beta version and test it in Beta of course?
Sorry but I need to make this framework in sql server and / or firebir, what classes should I use to implement the components of ZEOS.
Thanks
I went to this link http://synopse.info/fossil/info/0088bc5396 I downloaded zip Archive: Synops OpenSource-0088bc539614c694.zip
Hi, when compiling the version e9cafa3892879d29 this error occurs:
"endeclared identifier : TSQLCache"
in class :
TSQLDataBase = class
private
fDB: TSQLite3DB;
fFileName: TFileName;
fTransactionActive: boolean;
fLock: TRTLCriticalSection;
/// if not nil, cache is used - see UseCache property
fCache: TSQLCache;
.....
ok thanks, I just tried your modification and it works very well thanks again.
Now I have to create a program that manages all the files that I want to run the server, and then be able to create client programs that connect to different server files db3.