You are not logged in.
I've just installed windows11 on a new computer and had difficulties with mORMot1 and odbc-driver against latest MSSQL DB.
I had to add some code in SynOleDB:
{ TOleDBMSSQL2018ConnectionProperties }
procedure TOleDBMSSQL2018ConnectionProperties.SetInternalProperties;
begin
if OSVersion>wVista then
fProviderName := 'MSOLEDBSQL';
inherited SetInternalProperties;
end;Hope this is correct or...
Well, my library settings in delphi fooled me,
My library settings in delphi/mormot was ../mORMot/static and not ../mORMot/sqlite3/static as it was before.
In mORMot2 it is set as:
{$L ..\..\static\delphi\sqlite3.o} CPU64
{$L ..\..\static\delphi\sqlite3.obj} CPU32
And that worked as it was the same as in github.
But in mORMot1 it is:
{$L sqlite3.o} CPU64
{$L sqlite3.obj} CPU32
So I needed to put the files ../mORMot/static/ instead of ../mORMot/sqlite3/static as what you get when you pull from github.
So... sorry my fault again.
Few weeks ago I pulled a new version of mORMot2 and got the message of SQLite outdated version, ok I downloaded the static files and I was back on track again.
Today I pulled the latest version of mORMot1 and tried to compile/run an older Mormot1 project but got the error message also this time.
I've downloaded the static files but still got the message. Then I renamed all versions of the files I found and tried compile/run again I still get the same message:
"Linked version is 3.44.2 whereas the current/expected is 3.46.1."To me it seems to be an existing file left somwhere that is accessed but where can it be?
I have checked delphi settings and it looks all ok.
So I need some ideas what to do/look at.
Thank's in advance!
I am trying to help a friend using mORMot2 by giving him some examples but have hard to make some of them to work.
I thought I could use some of the examples in the "ex"-folder but failed to compile some of them.
Here I show the problems with tbo:s example:
04-HttpServer-InterfaceServices
This one I could make to work though:
TestRestClient.dpr
unit frm_Main;
if FDocumentService.Client.SetUser(pmcUserName, TAuthUser.ComputeHashedPassword(pmcPassword), True) then // - Does not compileI added pmcUserName:
if FDocumentService.Client.SetUser(pmcUserName, TAuthUser.ComputeHashedPassword(pmcUserName,pmcPassword), True) then // - Compile
Have not found a solution for this:
TestRestServer.dpr
unit u_ServiceServer;
if IsValidJson(json)
and (DynArrayLoadJson(customers, json, TypeInfo(TCustomerItemArray)) <> Nil)// - Does not compile - "Incompatible types"So I need some help to fix this code and wonder how this could happend?
Have mormot2 later updates caused this or have I missed something?
That was a big difference!
Perfect!
But I could not use _ObjFast I needed to change to _JsonFast like:
TDocVariantData(fOrderLines).AddItem(_JsonFast(RecordSaveJson(pmcOrderLine, TypeInfo(TOrderLine))));That really helped, but what did you meen with "AdditemRtti() method?
I couldn't give up compleatly and I found an article which helped me finally.
link: https://blog.synopse.info/?post/2024/02 … hi-and-FPC
I'll put my solution here but want to ask for comment on this solution and if there are better way to do it.
function TForm2.addMember(const pmcFam: TOrmFamily;
const pmcMbr: TMember): boolean;
var
Jss, js, js2: RawByteString;
val: variant;
list,list2: IDocList;
Dict: IDocDict;
f: TDocDictFields;
DocVariant: TDocVariant;
v: variant;
doc: TDocVariantData;
begin
Js := RecordSaveJson(pmcMbr, TypeInfo(TMember));
val := _JsonFast(js);
js2 := _JsonFast(pmcFam.Members);
list := DocList(js2);
List.Append(val);
v := List.AsVariant;
if list.Len > 0 then
while list.PopItem(v) do
begin
assert(list.Count(v) = 0); // count the number of appearances
assert(not list.Exists(v));
Listbox1.Items.Add(v.Name); // late binding
dict := DocDictFrom(v); // transtyping from variant to IDocDict
// enumerate the key:value elements of this dictionary
for f in dict do
begin
Listbox2.Items.Add(f.Key);
Listbox3.Items.Add(f.Value);
end;
end;
end;Ive been working for hours to make it work search through google without finding anything that work. Google AI answers looks nice but they are compleatly wrong, all of them.
So I finally gave up and hope I can get an answer here.
Some code:
type
TOrmFamily = class(TOrm)
private
fFamilyName: RawUTF8;
fMembers: Variant;
published
property FamilyName: RawUTF8 read fFamilyName write fFamilyName;
property Members: variant read fMembers write fMembers;
end;
TFamilyArray = array of TOrmFamily;
TMember = Object//packed record
Name: RawUTF8;
Age: integer;
end;
fam1 := TOrmFamily.Create;
fam1.FamilyName := 'Larson';
fam1.fMembers := '';
addFamily(fam1);
mbr11.Name := 'Tommy'; mbr.Age := 45;
addMember(fam1, mbr11);
mbr12.Name := 'Linda'; mbr.Age := 43;
addMember(fam1, mbr12);
function TForm2.addFamily(const pmcFam: TOrmFamily): boolean;
var
ID: TID;
begin
ID := Server.Server.orm.Add(pmcFam,true);
result := ID > 0;
end;
function TForm2.addMember(const pmcFam: TOrmFamily;
const pmcMbr: TMember): boolean;
var
Jss, js: RawByteString;
DocVariant: TDocVariant;
v: variant;
doc: TDocVariantData;
begin
end;
Expected result:
[{"name":"Tommy","age":45},{"name":"Linda","age":43}]]It's no idea to show all tests i've done here but it is the function "addMember" where I like to make this work. It show some variables I used in my tests.
Super that worked! I easily get confused when there are so many options.
Now I have:
Server := TRestServerDB.Create(fModel);
fDBserver := Server.server;and thats it!
I just want a handle that I can use to read and write data from a MSSQL database as I can in the old mormot.
I thought I could use the same code as I used in mormot1 but it doesnt look like that.
I've tried a lot of different ways but this is the closest I got. That's why it looks confusing.
I've tried to find any example about external databases but everything is about sqlite3 and I have no problems with that using sqlitebased mormot.
An example of code where I query the database in the old mssql/mormot-version can look like this:
user := TOrmUsers.Create;
user.FillPrepare(fDBServer, 'ID=?', [aUserID]);
if user.FillOne then begin
clientNo := user.companyNo;
result := user.fFirstName + ' ' +user.LastName;
end;Try to work with MSSQL but fails using this code:
constructor TTest.create(const aConnection: TStrings);
var
model: TOrmModel;
connection: TsqlDBConnectionPropertiesClass;
serverName, DBName, UserID, Passw: RawUTF8;
rest: TRestServerFullMemory;
begin
fModel := TOrmModel.Create([TOrmUsers], '');
connection := GetODBCDriverSpec;
serverName := aConnection.Values['Server'];
DBName := aConnection.Values['Database'];
UserId := aConnection.Values['User_Name'];
Passw := aConnection.Values['Password'];
fProps := connection.Create(serverName, DBName, UserID, Passw);
VirtualTableExternalRegister(fModel, TOrmUsers, fProps, 'dbo.Users');
fModel.Props[TOrmUsers].ExternalDB.MapField('ID', 'UserID');
fModel.Props[TOrmUsers].ExternalDB.MapField('UserEmail', 'Description');
rest := TRestServerFullMemory.create(fModel);
fDBServer := TRestOrmServerDB.Create(rest); // <<--- occurs here!
try
fDBServer.CreateMissingTables;
finally
end;
end;Thanks! I had missed a couple of units, after correcting that I could go on and now made it work.
ODBC?... well I have used this type for many years and had no idea of that key. Is there some benefits by using OleDB keys?
I'll look at this later on.
I get the following error compiling the code below
E2010 Incompatible types: 'TSqlDBOleDBConnectionProperties' and 'class of TSqlDBOleDBMSSQL2012ConnectionProperties'
function TMMBaseDB.GetODBCDriverSpec: TOleDBConnectionProperties;
const
ODBCDriverKey_2018 = '\SOFTWARE\ODBC\ODBCINST.INI\ODBC Driver 17 for SQL Server';
ODBCDriverKey_2012 = '\SOFTWARE\ODBC\ODBCINST.INI\SQL Server Native Client 11.0';
ODBCDriverKey_2008 = '\SOFTWARE\ODBC\ODBCINST.INI\SQL Server Native Client 10.0';
begin
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE; //2147483650;//
if OpenKeyReadOnly(ODBCDriverKey_2012) then
begin
result := TOleDBMSSQL2012ConnectionProperties;
CloseKey;
end
else if OpenKeyReadOnly(ODBCDriverKey_2008) then
begin
result := TOleDBMSSQL2008ConnectionProperties;
CloseKey;
end
else
result := TOleDBMSSQLConnectionProperties;
finally
Free;
end;
end;I can not understand this as it is declared in unit "mormot.db.sql.oledb" like:
TSqlDBOleDBMSSQL2012ConnectionProperties = class(TSqlDBOleDBMSSQLConnectionProperties)Hope I can get some help solving this, the code is converted from an old mormot-1 unit, and it worked there.
This is my uses clause:
uses
mormot.core.base
, mormot.orm.base
, mormot.orm.core
, mormot.rest.server
, mormot.db.sql.oledb
, mormot.orm.sql
, system.classes
, Winapi.Windows
;Ok, I found the reason... The linker searches the path: "/home/larand/fpc-library/mORMot2/static/x86_64-linux" but of some reason I got all files directly under the "static" folder.
I could have looked up a bit better. ![]()
Sorry I forgot to tell that I also added the static library. Here is what I got there:
larand@larand-VirtualBox:~$ ls fpc-library/mORMot2/static
crc32c64.o libdeflatepas.a quickjs.o sha512-x64sse4.o
dev.sha256 liblizard.a README.md sqlite3.o
larand@larand-VirtualBox:~$ Running Lazarus-3.6 on Ubuntu-20.04 using oracle vm.
I followed the instructions on GIT-ReadMe
"On Lazarus:
Just open and compile the /packages/lazarus/mormot2.lpk package;
and mormot2ui.lpk if needed.
"
And it executed without problem.
But when I tried to compile the example code I got the following messages:
Compile Project, Target: /home/larand/fpc-library/mORMot2/ex/http-server-files/exe/httpServerFiles: Exit code 1, Errors: 1, Warnings: 6
httpServerFiles.dpr(34,1) Warning: Library libdeflatepas.a not found, Linking may fail !
httpServerFiles.dpr(34,1) Warning: Object ../../static/x86_64-linux/sha512-x64sse4.o not found, Linking may fail !
httpServerFiles.dpr(34,1) Warning: Object ../../static/x86_64-linux/crc32c64.o not found, Linking may fail !
Warning: linker: /usr/bin/ld: cannot find ../../static/x86_64-linux/sha512-x64sse4.o: No such file or directory
Warning: linker: /usr/bin/ld: cannot find ../../static/x86_64-linux/crc32c64.o: No such file or directory
Warning: linker: /usr/bin/ld: cannot find libdeflatepas.a: No such file or directory
httpServerFiles.dpr(34,1) Error: Error while linkingIt is probably something wrong with my setup of lazarus but I have no idea.
The reason for me to use ubuntu and lazarus is to create an application running on a PI-Zero2W having it to send messages over internet.
//LG
I try to convert the "mormotDDD" unit to be used by mORMot2 because I like to use "CQRS" the way it is used in the old mormot DDD-example.
It seemed to be an easy task from the beginning but I'm stopped by a few things.
The TClassInstance is not available in mORMot2. It look like "TRttiClass" could be used here but it is not defined the same.
The " property Aggregate: TClass read fAggregate.rttiClass ;" does not work as rttiClass is a function and not a field.
There are a few more things to fix but I think this is the most important to fix. The other may be solved easier when this is solved. Otherwise I'll come back and ask for more help.
I'll go for that, thanks ab.
I'm not sure I understand the last sentence. I can show you the last part of the jsonfile if that helps.
"DetaljReferens": [
{
"Referens": null,
"Referens_ReferensLista": "BSAB96:PR",
"Referens_ReferensKod": ""
},
{
"Referens": null,
"Referens_ReferensLista": "SBEF:Byggdel",
"Referens_ReferensKod": "90"
},
{
"Referens": null,
"Referens_ReferensLista": "PRODKOD",
"Referens_ReferensKod": ""
}
]
}
}
]
}
}
}It has a fixed fields layout. I think it is created from a XML-file.
Just below 1MB > 24000 lines.
9 levels.
The json file I got is a very big one with lot of levels and would normally be split up into several tables but I have been asked to make one flat table of it.
To me it looks as very complicated task to solve so I would be happy to get some help to put me in the right direction.
I suppose that there are some very useful code in mormot. I've been looking a round a bit but it isn't that easy.
I have another version written for Lazarus if that could be easier for someone to checkout.
https://gitlab.com/GIT-Testing/mormot-r … th-lazarus
This version works as bad as any other of my attempts to find a working solution.
Looks that it is not possible to have the real-time sync with this library.
//LG
Please see my updated reply above.
It seems that it only works once after that I erase the user table first and then start the slave.
The data is copied from master to the slave just after the call:
fSlave.RecordVersionSynchronizeSlaveStart(TOrmUser, fMasterClient, nil);But not after.
Very strange or...?
There is an error in the json structure
{
"c": "28403.81000000",
"a": "28420.61000000",
"A": "0.00351000", <--- THIS COMMA is not valid here.
},
You can use this link: https://jsonlint.com/
Best regards
//LG
Hello ab,
I've already checked out that code and I did a new attempt with a small testproject but still fail.
I have this project available as a zip-file but I don't find any way to share that. PasteBin doesn't seem to to be used with anything but sourcefiles.
Any idea how I can share this file?
I have the project on GITLAB if it could work?
https://gitlab.com/GIT-Testing/test_mor … cation.git
I made a small program that more or less copies the code you have in your test suite.
That code works but the difference is that I don't use services here. When simulating changes in the master table I do it directly through the TRestServerDB instance.
But in the real world I need to use services and then I need 2 different http-channels, one for update the table on the master and one for the replication.
And this case don't work for me. See the the GITLAB-project above.
I'm sure that I have misunderstood how to do this correct but I'm also sure it must be someone, that have a working solution of a similar system like mine, that could see what I've done wrong or..?
Otherwise I have to develop a compleatly different solution on my own :-(
Please help.
No answer in a week, I hoped to find some anwer here at least a comment if some necessary information is missing.
I tried to find a solution myself and I feel that I've done what is needed but in spit of that, no success.
I don't believe that this function is incomplete or not functional in mORMot2 but it looks so to me. ![]()
Only when the master server is restarted the sync works but only once.
In the slave log I can see the following repeated five times:
2023-10-05 09:24:14.640 Debug mormot.rest.sqlite3.TRestServerDB(035da1e0) RecordVersionSynchronizeSlaveStart(TORMUser) current=19 Subscribe(036ec488)
2023-10-05 09:24:14.640 Enter mormot.soa.client.TServiceFactoryClient(036fac98).InternalInvoke IServiceRecordVersion.Subscribe("User",19,1)
2023-10-05 09:24:14.640 Enter mormot.rest.http.client.TRestHttpClientWebsockets(03d93730).InternalUri POST
2023-10-05 09:24:14.640 Trace mormot.rest.http.client.TRestHttpClientWebsockets(03d93730) InternalRequest POST calling THttpClientWebSockets(03d939a0).Request
2023-10-05 09:24:14.640 Client mormot.rest.http.client.TRestHttpClientWebsockets(03d93730) POST DHSSync/ServiceRecordVersion.Subscribe status=200 len=18 state=1
2023-10-05 09:24:14.640 Leave 00.003.082
2023-10-05 09:24:14.640 Service return mormot.soa.client.TServiceFactoryClient(036fac98) {"result":[false]}and then I get an error:
2023-10-05 09:24:14.704 Error mormot.rest.sqlite3.TRestServerDB(035da1e0) RecordVersionSynchronizeSlaveStart(TORMUser): retry failure The code in the slave looks like this:
procedure TForm5.btnSynchronizeClick(Sender: TObject);
function setUpSyncServer: TRestServerDB;
begin
result := TSQLRestServerDB.Create(CreateSyncModel, ChangeFileExt(Executable.ProgramFileName, '.db'));
result.DB.Synchronous := smOff;
result.DB.LockingMode := lmNormal;
result.Server.CreateMissingTables;
end;
begin
if not fSyncRunning then
begin
btnSynchronize.Caption := 'Stopp Synk';
fSyncServer := SetUpSyncServer;
fHttpClientSync := TRestHttpClientWebSockets.Create('127.0.0.1', '8888', CreateSyncModel);
fSyncServer.RecordVersionSynchronizeSlaveStart(TORMUser, fHttpClientSync);
fSyncRunning := true;
end
else
begin
btnSynchronize.Caption := 'Synka';
fSyncServer.RecordVersionSynchronizeSlaveStop(TORMUser);
freeAndNil(fSyncServer);
freeAndNil(fHttpClientSync);
fSyncRunning := false;
end;
end;The master part:
function setUpOrmSyncServer: TRestServerDB;
begin
result := TRestServerDB.Create(CreateSyncModel, ChangeFileExt(Executable.ProgramFileName, '.db'));
result.DB.LockingMode := lmNormal;
end;
begin
OrmSyncServer := setUpOrmSyncServer;
HttpSyncServer := TRestHttpServer.Create('8888', [OrmSyncServer], '+', UseBidirSocket,4 );
OrmSyncServer.RecordVersionSynchronizeMasterStart;So I just wonder, What am I missing?
Ok, I've done that already but as the array can contain several hundreds of object in the worst case I thought that using a dynamic array could be more effective.
In this case, load and response time is not an issue but I like to be more effective and I can think of cases where this could be an issue.
And why not to be prepared?
I have a class that contains an array where I need to find a certain object in this array as I want to update this certain object.
I've tried to find examples of how to do this but still failed so my hope is that someone could have such an example to show how this could be done.
Thanks in advance!
I would like to inform the client when trying to add an already existing record.
But the exception from sqlite3 is not forwarded. The call IRestOrm.add just return zero and the exception can only be seen in the server log.
How could I solve this?
Thanks Thomas, excelent solution even though it didn't help eliminate the invalid pointer operation.
Thanks ab, your comment woke me up, I asked myself why I use the whole objects in the parameter list when I only need the ID:s.
So I replaced those parameters with the id:s of the objects and now everything is alright again. ![]()
I have two classes TArticle and TSubProject. A SubProject can contain several articles.
Articles can be added by demand to the subproject.
I'm using "ObjArrayAdd" to add new articles to the subproject.
Like: ObjArrayAdd(aSubP.Articles, aArticle);
But that's not allowed - I get this message from delphi: "Constant object can not be passed as var parameter"
So I tried to use an intermediate variable and that calms delphi but executing the program gives me another error:
"Invalid pointer operation" when the function exits. But the database is updated then.
I' understand that I do something really wrong but how should I do?
The repository:
function TDHSSyncRepository.addArticleToSubProject(var aSubP: TSubProject;
out aArticle: TArticle): TSyncRepoError;
var
s: TArticleObjArray;
begin
if RetrieveArticle(aArticle) <> srSuccess then begin
result := srNotFound;
exit;
end;
Result := srNotFound;
// --- --> ObjArrayAdd(aSubP.Articles, aArticle); <<--- "Constant object can not be passed as var parameter
s := aSubP.Articles; // <<---- Do this instead
ObjArrayAdd(s, aArticle); // << -- Works but gives "Invalid operation"
aSubP.Articles := s; //
end;Best regards,
LarsG
Oh, I got your answer while I was writing.
Yea, I can see now!
Maybe I was not completely wrong about the parameter..?
I took the code from an example just to get a kickstart for testing.
I should be more careful.
Thank's a lot!
Sorry, I found the problem. It's of course my mistake. I misunderstood the usage of the parameter "ContractExpected". It looks like it should have the same name as the service without the leading 'T'. I got the impression of that this parameter is used to make it possible of same version control of the interface. So if you add a new or changed a method you could change this parameter and in that way you get a signal if you have different versions between client and server.
Strange is that I'm sure I had a different name for this parameter from the beginning without any problem.
Sorry I bothered you with this.
Best regards
Lars-G.
To make a simple test client I added the following code:
procedure TForm4.FormCreate(Sender: TObject);
begin
Model := TOrmModel.Create([],SYSTEMLocalROOT);
HttpClient := TRestHttpClient.Create(IP_Local, HTTP_PORT, Model);
HttpClient.ServiceDefine([IDHSLocalService], sicShared, DHS_LOCAL_CONTRACT);
HttpClient.Services[DHS_LOCAL_CONTRACT].Get(fDHS_LocalService);
end;In the function "TServiceContainerClientAbstract" the parameter aInterfaces contains one interface "IDHSLocalService" which is correct here. I' only use one interface so far.
The call "fHash.FindOrNew(fHash.HashOne(@Item), @Item, nil);" with Item as 'DHS_LOCAL_CONTRACT' returns -161.
This lead to that he interface pointer will be nil.
I'm not sure how to reproduce with a RawUTF8 list of interface. Where should I put the call?
Suddenly my testclient crashed at start with an access violation in this call: "HttpClient.Services[DHS_LOCAL_CONTRACT].Get(fDHS_LocalService);"
Debugging showed that the function "fInterfaces.FindHashed(aUri)" returns -1.
I've just added a method to the interface, recompile both the server and client and then this happened. I also removed those changes but still the same problem.
Something else must have been changed but I can't imagine what it could be.
I need some idea of where to start looking. ![]()
I solved it by replacing IList with an ordinary dynamic array for the service. It requires some more coding but it works. I kept using IList in the repository though as I can initiate the collection in the service before calling the repository methods.
It seems to require too much effort to be worth solving ?
I'm very fond of IList but I'm trapped by the fact that I have to declare it as a constant in the parameter list on a service method.
So there is no way to initialize it. ![]()
I'm sure that there is a solution to this but at the moment I'm lost.
That looks good, I will soon test it.
Is there a way to have mormot create one index using two or more fields?
Beutifull! Thanks!
This is the result:
function TDHSSyncRepository.GetAllArticles(var aArts: TOrmArticles):TSyncRepoError;
var
ormArt: TOrmArticle;
begin
result := srNotFound;
FRestOrm.RetrieveIList(TOrmArticle, aArts);
if aArts.Count < 1 then
exit;
result := srSuccess;
end;I get this error when the IList<TOrm> is zero referenced after using CreateAndFillPrepare.
// TOrmArticles is the same as IList<TArticle>
function TDHSSyncRepository.GetAllArticles(var aArts: TOrmArticles):TSyncRepoError;
var
ormArt: TOrmArticle;
i: integer;
begin
result := srNotFound;
i := 0;
// result := Collections.NewList<TOrmArticle>; //Tested doing this call outside/inside this function but same result.
ormArt := TOrmArticle.CreateAndFillPrepare(FRestOrm,'',[]);
while ormArt.FillOne do begin
aArts.Add(ormArt);
end;
result := srSuccess;
end;When aArts no longer used I get the error.
What's wrong here?
Ok, I took a snap from my code and removed a lot of irrelevant code and changed the names in hope that it would be easier to read.
The "names" is just a packed record. I included it in the snap now.
Well, your suggestion worked perfectly.
I remembered when I saw it that I used it before but my memory is just a... memory now I'm afraid.
How should I deal with fields that sometimes contain NULL-values when using variants
The code below shows how I tried to deal with it.
You can't even check if the field is null before using it.
The only way I know is to have a
Try
exceptaround each assignment but that doesn't taste good.
I'm sure there is a better solution but I'm lost.
type
TNames = packed record
field1: integer;
theNullField: RawUTF8;
field3: RawUTF8;
end;
var
I: isqldbrows;
row: variant;
names: TNames;
begin
I := Props.execute('select * from dbo.mytable where name = ?', ['Peter']);
if I.Step(true) then begin
I.RowDocVariant(row,[]);
names.fImportDir := row.Field1;
if not row.theNullField. = null then // This raise an exception
names.theNullField := row.theNullField // This also raises an exception if executed.
else
names.theNullField := '';
names.Field3 := row.Field3;
I.ReleaseRows;
end;Ok, that worked well, so many thanks.
I think there are a lot of different ways of doing this and it's hard to find out which method to use.
The project I'm working on now is a replacement of an existing function to make it much faster so the speed is the main purpose of this project.
The reason I want the data of the array stored as JSON is mainly to have better control when testing, perhaps when the application is tested and works well I might consider going back to blob-storage.
But it is still nice to have the possibility to check out the contents in the database.
Any ideas or suggestions are very welcome.
best regards
Lars
Ok, thanks a lot for the almost complete code.
But this one store the week array as a blob, how about having it stored as a JSON string? Wouldn't I need to register the array for JSON? And what more?
with best regards
Lars
Sorry, the JSON I wrote is not a real JSON array I only typed it in by hand into the database record to test my program.
I'm not sure about how a json string should look to correspond to my class so I'm not surprised that it's not correct.
A Week is a packed record with the name TWeek and then I declared the array TWeekArray from TWeek.
This Array is contained in a class: TWeeks and this class is the one I want to persist in a sqlite3-table. In fact, later I want to have it in an IN-Memory table but in the beginning, I will have it in a database during the test.
So the question is, how can I best persist this table, TWeeks, you have it at the beginning of this thread.
Forget about the JSON string.
Ok, the compiler is now satisfied but I still missing the data for the WeekArray.
The field "Week" in the db looks like : '{"currentYear": 2023,"ActualWeek": 8,"weeks": [{"ryear": 2023,"rindex": 1,"rweekno": 8,"rAvailableAmt": 186,"rRequiredAmt": 99}]}'.
It's a valid json string but I'm not sure if it is valid in this case?
Where can I find TRtti? I use System.rtti but that won't help.
Ok, I found it in mormot.core.rtti.
But I couldn't use TRtti but Rtti.
I have a class of TSynPersistent containing an array of records that I want to populate from a DB-table.
For the moment while testing, I use SQLite3.
I worked out a TOrm descendant used for reading the data.
Everything reads correctly except for the array which is nil.
I thought I didn't need to register but I now realized that I was wrong.
But I don't know how to do it. Following instructions from the documentation I tried this:
The record:
TWeek = packed record
rYear: TYear;
rIndex: TWeekBufferIndex;
rWeekNo: TWeekNo;
rAvailableAmt: TAvailableAmt;
rRequiredAmt: TRequiredAmt;
function getAvailableOnWeek: TAvailableOnWeek;
property availableOnWeek: TAvailableOnWeek read getAvailableOnWeek;
end;
TWeekArray = array of TWeek;The class:
TWeeks = class(TSynpersistent)
private
fWeekArray : TWeekArray;
fActualWeek : TWeekNo;
public
function getWeek(index: integer): TWeek;
procedure SetWeek(const index: integer; aValue: TWeek);
published
property weekArray: TWeekArray read fWeekArray write fWeekArray;
end;The registration:
initialization
var T: Pointer;
T := TypeInfo(TWeekArray);
TJSONSerializer.RegisterObjArrayForJSON(T,TWeekArray);The TOrm descendant:
TOrmWeeks = class(TOrm)
private
fWeeks : TWeekArray;
fActualWeek : TWeekNo;
protected
public
constructor create;
published
property ActualWeek: TWeekNo read fActualWeek write fActualWeek;
property Weeks: TWeekArray read fWeeks write fWeeks;
end;The problem is that the compiler doesn't like this: " TJSONSerializer.RegisterObjArrayForJSON(T,TWeekArray);"
It say's: [dcc32 Error] dddLOBTypes.pas(294): E2029 '(' expected but ')' found
and next error: [dcc32 Error] dddLOBTypes.pas(295): E2250 There is no overloaded version of 'RegisterObjArrayForJson' that can be called with these arguments
If I replace TWeekArray with a class the compiler will be satisfied.
So what do I missing here?
So there are no plans to make a new one then?