#51 mORMot 2 » Multiple field index » 2023-05-05 06:37:49

larand54
Replies: 5

Is there a way to have mormot create one index using two or more fields?

#52 Re: mORMot 2 » Invalid pointer operation when using IList with CreateAndFillPrepare » 2023-05-03 21:01:51

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;

#53 mORMot 2 » Invalid pointer operation when using IList with CreateAndFillPrepare » 2023-05-03 17:27:11

larand54
Replies: 2

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?

#54 Re: mORMot 2 » How to avoid exception from fields containing null values? » 2023-03-30 10:33:08

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.

#55 mORMot 2 » How to avoid exception from fields containing null values? » 2023-03-30 09:41:41

larand54
Replies: 2

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
except

around 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;

#56 Re: mORMot 2 » Serializing an array of records How To? » 2023-02-23 11:04:33

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

#57 Re: mORMot 2 » Serializing an array of records How To? » 2023-02-23 09:01:35

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

#58 Re: mORMot 2 » Serializing an array of records How To? » 2023-02-22 17:05:27

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.

#59 Re: mORMot 2 » Serializing an array of records How To? » 2023-02-22 10:04:57

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?

#60 Re: mORMot 2 » Serializing an array of records How To? » 2023-02-22 09:53:53

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.

#61 mORMot 2 » Serializing an array of records How To? » 2023-02-22 08:52:22

larand54
Replies: 12

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?

#62 Re: mORMot 2 » DDD / ORM mapping - PODO -> TOrm » 2023-02-18 15:57:44

So there are no plans to make a new one then?

#63 mORMot 2 » DDD / ORM mapping - PODO -> TOrm » 2023-02-18 13:59:30

larand54
Replies: 3

Is there an alternative to mORMot_1:s TDDRepositoryRestFactory.ComputeSQLRecord ?

It would be handy to have one, I've been searching for a while but have not found any.

#64 Re: mORMot 1 » MongoDB - Unsupported OP_QUERY command: hostInfo » 2023-01-17 10:56:55

Ok, that's good. As I'm new to MongoDB it also makes sense to start MongoDB with mORMot2.
When I tried to set up mORMot2 on Delphi and followed the instructions from the ReadMe file I got this code to work.
:-)

#65 mORMot 1 » MongoDB - Unsupported OP_QUERY command: hostInfo » 2023-01-17 09:19:06

larand54
Replies: 2

Completely new to MongoDB and tried one of your old examples:
https://blog.synopse.info/?post/2014/05 … ase-access

Installed the latest version (6.03) of MongoDB
and tried:

var Client: TMongoClient;
    DB: TMongoDatabase;
    serverTime: TDateTime;
    res: variant; // we will return the command result as TDocVariant
    errmsg: RawUTF8;
begin
  Client := TMongoClient.Create('localhost',27017);
  try
    DB := Client.Database['mydb'];
    writeln('Connecting to ',DB.Name); // will write 'mydb'
    errmsg := DB.RunCommand('hostInfo',res); // run a command
    if errmsg<>'' then
      exit; // quit on any error
    serverTime := res.system.currentTime; // direct conversion to TDateTime
    writeln('Server time is ',DateTimeToStr(serverTime));
  finally
    Client.Free; // will release the DB instance
  end;
end;

and gets: 'Unsupported OP_QUERY command: db.hostInfo. The client driver may require an upgrade. For more details see https://dochub.mongodb.org/core/legacy-opcode-removal'

Don't know if its possible use the latest version with mORMot1 any more or should I try with mORMot2?

#66 mORMot 1 » Join several levels » 2022-01-20 18:36:04

larand54
Replies: 1

Trying to  find the best way to solve the problem with tables in multiple levels as the following example:

TSQLLevel0 = TSQLRecord
private
  fName: RawUTF8;
published  
  property name: RawUTF8;
end;
 
TSQLLevel1 = TSQLRecord
private
  fName: RawUTF8;
published  
   property L1Name: RawUTF8;
   property lev0: TSQLLevel0 read fLev0 write fLev0;
end;

TSQLLevel2 = TSQLRecord
private
  fName: RawUTF8;
published  
   property L2Name: RawUTF8;
   property lev1: TSQLLevel1 read fLev1 write fLev1;
end;

Tried with CreateJoined but that could only be used on two levels only i.e. Level0 and level1.
Any suggestions would be appreciated.

#67 Re: mORMot 1 » Login fails using TSynConnectionDefinition » 2022-01-01 12:46:19

I don't understand exactly what you meant but I did like this:

fStore: TSynConnectionDefinition;
pw: RawUTF8
    pw := TSynConnectionDefinition.ComputePassword('myPassword');
    fStore := TSynConnectionDefinition.CreateFromJSON(StringToUtf8('{	"Kind": "TOleDBMSSQL2012ConnectionProperties", '
          + '"ServerName": "MyServer\\SQLEXPRESS", "DatabaseName": "MyDB", "User": "username", "Password":  "'+pw+'"}'));
    fDBServer := TSQLRestExternalDBCreate(fModel, fStore, USE_AUTHORIZATION, []);

And that worked, but that wasn't exactly what you said?

#68 mORMot 1 » Login fails using TSynConnectionDefinition » 2021-12-31 12:20:32

larand54
Replies: 2

It looked to be convenient to use "TSynConnectionDefinition" but I failed to make it work.
Login failed due to missing password.

My code look like this:

fStore: TSynConnectionDefinition;
 
 fStore := TSynConnectionDefinition.CreateFromJSON(StringToUtf8('{	"Kind": "TOleDBMSSQL2012ConnectionProperties", '
          + '"ServerName": "MyServer\\SQLEXPRESS", "DatabaseName": "MyDB", "User": "username", "Password": "myPassword"}'));
    fDBServer := TSQLRestExternalDBCreate(fModel, fStore, false, []);

TSQLRestExternalDBCreate looks for fStore.PasWordPlain which does not exist in fStore.

What's wrong with my assumption?

#69 mORMot 1 » Complex join with createJoined » 2021-12-19 17:45:21

larand54
Replies: 1

Is the following SQL realizable with the "TSQLRecord.createJoined" function or is there better alternatives?

I try to avoid running the SQL-script in the program due to fear of"SQL-Injection".
It's about an old legacy database. I have tested the function in simpler case where you use only one common field which work perfectly.

SELECT TE.AddressName, TC.Customername FROM tbl_A TA
 join tbl_B TB ON TB.CustomerNo = TA.CustomerNo
 join tbl_C TC ON TC.CustomerNo = TA.CustomerNo
 join tbl_D TD ON TD.CustomerNo = TA.CustomerNo AND TD.AddressNo = TC.AddressNo
 join tbl_E TE ON TE.AddressNo = TD.AddressNo

#70 Re: mORMot 1 » Cannot insert from RestServer » 2021-12-06 16:20:03

Sorry, I fixed it by deleting the table and then run the program again. But Yes I created the table with mORMot but I also have tested different Restservers and it might have been created different then.
I tested TSQLRestClientDB but could not understand how I should set it up. As I don't use SQLITE this time I could not put a filename into the third parameter, I did try but then it created a db3-file with some strange marks ('v') on the tables.

#71 mORMot 1 » Cannot insert from RestServer » 2021-12-06 15:23:01

larand54
Replies: 2

I have a small project here where I included everything in one program because it only is about updating a single file with a text field.
My problem is that when the server tries to add a record I'll get an error which says in short: "Cannot insert explicit value into ----- when IDENTITY_INSERT is set to OFF"

I'm running Delphi11 and MSSQL.

Links to part of the code: [URL https://1drv.ms/u/s!AkzgaKIeNifrhaQI3gC … A?e=SpWAz3 /url]

the error message: [URL https://1drv.ms/u/s!AkzgaKIeNifrhaQLwLN … w?e=02zydi /url]

#72 Re: mORMot 1 » Error code: 406 fail on aggregate (ORM.add) » 2021-09-13 17:17:34

Ok, thanks.
Yes, the problem was that I didn't use "TSynAutoCreateFields". After changing that, all is now well.

#73 mORMot 1 » Error code: 406 fail on aggregate (ORM.add) » 2021-09-09 14:00:21

larand54
Replies: 2

This happens when I use a class that have references to another class.
see below:

  TLogType = class(TSynPersistent)
    private
      fName: RawUTF8;
      fValue: integer;
    published
      property name: RawUTF8 read fName write fName;
      property value: integer read fValue write fValue;
  end;
  TLogTypeObjArray = array of TLogtype;


  TMyLog = class(TSynpersistent)
    private
      fLogdate: TDate;
      fComment: RawUTF8;
      fLogType: TLogType;    <<<<-- the reference
    published
      property logDate: TDate read fLogDate write fLogDate;
      property comment: RawUTF8 read fComment write fComment;
      property logType: TLogType read fLogType write fLogType;
  end;

The reference is flattened in the TSQLRecord so the field "LogType" will be two fields:
LogType_Name" and "LogType_value".

Don't have a clue any longer how to solve this. I have a small zip file of a test project to share but don't know where to put it.
The exception occurs in a section called "fake interface" in the mORMot unit.

Would appreciate any help to solve this. Also, a site where I could upload my little zip file (12k).

Maybe this link? https://1drv.ms/u/s!AkzgaKIeNifrhLQze1G … A?e=ZCbpMx

#74 Re: mORMot 1 » How to read from database feeding a filtered list without memory leak » 2021-07-07 13:57:05

Thanks, that was much better - I've already tested and it works perfectly! smile

#75 mORMot 1 » How to read from database feeding a filtered list without memory leak » 2021-07-07 08:14:37

larand54
Replies: 2

How to read from database feeding a filtering list without memory leakage?

I have a windows-service that reads data from a table into a TObjectList
which is customized to filter out some data i.e. duplicate records.
That's because I couldn't find out how to do that with SQL and mORMot.
I have created a solution that works but I think it might be a
smarter solution.
Anyone that can tell?

Here is my solution:
Alt 1.

Alt 1. Just need one list and the finally is simpler.
procedure TEvNServer.readPkgPrefix(out aPrefixList: TPrefixList);
var
  SQL: RawUTF8;
  ppf: TSQLPkgPrefix;
  newPkgPrefix: TSQLPkgPrefix;
begin
  SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
  ppf := TSQLPkgPrefix.CreateAndFillPrepare(fDBServer, SQL, [1]);
  aPrefixList := TPrefixList.create;
  try
    while ppf.FillOne do begin
      newPkgPrefix := TSQLPkgPrefix.create;       // Clone object before adding to list
      newPkgPrefix.assign(ppf);                   //
      if aPrefixList.add(newPkgPrefix) = -1 then  // if object not accepted by the list,
        newPkgPrefix.free;                        // it must be free:d, otherwise mem-leakage
    end;
  finally
    ppf.free;  // must be free:d otherwise mem-leakage
  end;
end;

Alt 2.

Alt 2. Dont need to clone and add the assign method to TSQLPkgPrefix class.
procedure TEvNServer.readPkgPrefix(out aPrefixList: TPrefixList);
var
  SQL: RawUTF8;
  ppf: TSQLPkgPrefix;
  tmpList: TObjectList<TSQLPkgPrefix>;
begin
  SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
  tmpList := fDBServer.RetrieveList<TSQLPkgPrefix>(SQL, [1], '');
  aPrefixList := TPrefixList.create;
  try
    for ppf in tmpList do begin
      if aPrefixList.add(ppf) = -1 then begin
        ppf.free;
      end;
    end;
  finally
    if assigned(tmpList) then begin
      tmpList.OwnsObjects := false;
      freeAndNil(tmpList);
    end;
  end;
end;

#76 Re: mORMot 1 » Problems with LogViewer and file rotation » 2020-11-05 11:09:59

Don't know where I should set these options/flags and what choices I have?
I skimmed through the Logviewers code but didn't found anything useful.

#77 mORMot 1 » Problems with LogViewer and file rotation » 2020-11-04 10:26:52

larand54
Replies: 4

If I open the logfile with the log viewer, while the program is running and produces lines to the log file, and watching it over time the log go nuts!
It seems that the log viewer holds the logfile so that log rotation can not rename the file but still copies and compresses the filecontents into the rotate-list of files.
As it can't begin with an empty file it continues to run the rotate cycle for each line that adds to the log. This will cause huge cpu and memory load.

Is there a way to avoid this and still view the log? It's too easy to forget to close the viewer and unwatched it can cause a mess.

Otherwise I really like the viewer.

#79 mORMot 1 » How create a json formatted array of records? » 2020-08-15 10:47:45

larand54
Replies: 2

I tried this:

var
  body: variant;
  i: integer;
  files: array of RawUTF8;
  atm: array of variant;
  t: variant;
begin
  setLength(files, 2);
  files[0] := 'C:\temp\Faktura_se.pdf';
  files[1] := 'C:\temp\din.pdf';
  TDocVariant.new(body);
  if high(files) > -1 then
  begin
    SetLength(atm, high(files) + 1);
    for i := 0 to high(files) do
    begin
      TDocVariant.new(atm);
      t.name := extractFileName(files[i]);
      t.value := fileToBase64(files[i]);
      atm[i] := t;
    end;
    body.FileAttachments := _arr([atm]);
  end;

but that just set FileAttachments to '{"FileAttachments":[null]}'

Is there a simple correction of this code?

#80 Re: mORMot 1 » SynCrtSock error 12019 when run in a VCL-app » 2020-08-15 10:33:14

Found the reason... it was a setting called "Use a Proxy" that was on. I never ever used a proxy before... just don't have a clue on how it was set.
Well, that's it.
Thank's a lot.

#81 Re: mORMot 1 » SynCrtSock error 12019 when run in a VCL-app » 2020-08-14 20:09:47

Ok, but it won't help me as it only works when WIN10 is not detected.
HttpRequest gives error when proxy is set to auto which it is when WIN10 is detected.

What can make it do that? I suppose it normally works with win10?

And when I added "{$R Vista.res}" into the console project it stopped work.

#82 mORMot 1 » SynCrtSock error 12019 when run in a VCL-app » 2020-08-14 10:22:16

larand54
Replies: 4

When executing TWinHTTP.Post I get this error when run in a VCL app but if I run an excact copy of the code in a console-app it works.
I have debuged but can't find out what causes this.
Nice if someone have a clue to work on..

I have DELPHI-10.3 in this case and the latest version of WIN10.

I've debugged a bit deeper and found that in the initialization of connection properties there is a selection using Automatic proxy or no proxy. This is controled by OS-Version.
If i run the VCL-app I get major-version=10 and minor=3 but in the console app I get Major=6 and Minor=2 and in that case I get NO_PROXY but in the VCL-app I get Automatic_Proxy.

And if I changed the value from Auto to NO-proxy, using debugger,  it works with the VCL-version.

I have no idea why it is like that and why it won't work with automatic_proxy.
I don't want to change anything in SynCrtSock so I still need some help.

#83 Re: mORMot 1 » How do I load a file into the body of a http-request » 2020-08-14 10:04:32

Thank's a lot, I've just solved it this way:

    TDocVariant.new(body);
    body.SendUser := aFrom;
    body.Message := aMessage;
    body.Subject := aSubject;
    body.ToRecipients := _Arr([stringReplace(aMailTo, ';', ',', [rfReplaceAll, rfIgnoreCase])]);
    body.CcRecipients := _Arr([stringReplace(aCC, ';', ',', [rfReplaceAll, rfIgnoreCase])]);
    if high(aAttachments) > -1 then
    begin
      for i := 0 to high(aAttachments) do
      begin
        TDocVariant.new(atm[i]);
        atm[i].name := extractFileName(aAttachments[i]);
        atm[i].value := fileToBase64(aAttachments[i]);
      end;
    body.FileAttachments := _Arr([atm]);
    end;

    messageID := TWinHTTP.Post(fOaSec.getMailURL, body, fOaSec.getMailHeader);

function FileToBase64(const aFileName: RawUTF8): RawUTF8;
var
  f: TStream;
  bytes: TBytes;
begin
  result := '';
  f := TFileStream.Create(afilename, fmOpenRead);
  try
    if f.Size > 0 then
    begin
      SetLength(bytes, f.Size);
      f.Read(bytes[0], f.Size);
    end;
    result := binToBase64(@bytes[0], f.size); //String(sb);
  finally
    f.free;
  end;
end;

#84 Re: mORMot 1 » How do I load a file into the body of a http-request » 2020-08-12 07:46:14

Yes, it's about a http-request.
The service requires a body that contans mailFrom, mailto, message etc. and the attached files with name and contentents encoded in Base64 .
Al is wrapped in a json structure:

{
    "SendUser": "senderName@somwhere.on.earth",
    "Message": "Hello",
    "Subject": "HelloSubject",
    "ToRecipients": [
        "receiver.theMartian@mons.olympus.on.mars"
    ],
    "CcRecipients": [
        "flash@titan.on.saturn"
    ],
    "FileAttachments": [
        {
            "Name": "spacetraveling.pdf",
            "Value": "N7I+GuZ4KclTXP7KXM3YRdh0BfKxnMpOv8s....        } // Filecontents base64-encoded
    ]
}

Part of the code that calls the sendmail service

var
  messageID: sockString;
  body: variant;
  atm: variant;
begin
  if getToken = '' then
    result := -1
  else begin
    TDocVariant.new(body);
    body.SendUser := aFrom;
    body.Message := aMessage;
    body.Subject := aSubject;
    body.ToRecipients := _Arr([stringReplace(aMailTo,';',',')]);
    body.CcRecipients := _Arr([stringReplace(aCC,';',',')]);
    if high(aAttachments) > -1 then begin
       TDocVariant.new(atm);
       atm.name := aAttachments[0];
	   .
	   . read and add file contents here - all attachments should be put into an array and then added to the body.
	   
    messageID := TWinHTTP.Post(fOaSec.getMailURL,body,fOaSec.getMailHeader);

#85 Re: mORMot 1 » How do I load a file into the body of a http-request » 2020-08-11 18:54:09

Ok, thank's for an answer but I has to send the mail through a service where everything is built around OAuth2. I have everything working and can send the mail but I need to know how I should do with the files that needs to be attached to the mail.
Indy will not help here.

#86 mORMot 1 » How do I load a file into the body of a http-request » 2020-08-11 16:27:27

larand54
Replies: 9

In a new project I need to send mail using OAUTH2. The mail can contain attachments like pdf-files and they need to be Base64 encoded.
I feel lost in all alternatives so I need some help to move forward.
I use TWinHttp.post sending mail. It works good with simple mail.

#87 Re: mORMot 1 » urlEncode don't convert the "tilde" character » 2020-08-10 16:15:55

Ok, I understand.
Well, good to know why it is like that, then it makes it more easy to accept.
In my case, for the moment at least, it won't be much of a problem as it is a fixed string that will not change often if ever so I only have to replace the '~':s with "%7E" manually.

#88 mORMot 1 » urlEncode don't convert the "tilde" character » 2020-08-10 10:56:09

larand54
Replies: 5

Tries to use OAUTH2 in a project but a secret code  contains '~'-characters and they are not replaced by the function.
While debugging I could se that this character belongs to the "unreserved characters" and will be left unchanged.

The OUTH2 service to get a token don't accept this character.

What can I do about it?
I no INDY has that function and that works but would like to make it without adding more libraries.

#89 Re: mORMot 1 » ORMAdd does not store the linked classes » 2020-05-10 17:08:50

Ok, from the beginning I did just that but I did not want a complete flat table, I want to split them in One Customer table and one PersonContactable table.
In this simple example it isn't needeed but I want to know how to behave when I really need to split.
In one case I can think of is when you have several contacts for the customer. They are specified by what "role" that contact have. Different customers has different roles One may have only one another has 3 and others may have 6 etc. In that case it feels inconvenient to have a flat table for all this even if its possible.
One contact can possess several roles, the customer employs a new person to take over another contacts role etc.


21_customer-role-contact.png

#90 mORMot 1 » ORMAdd does not store the linked classes » 2020-05-10 13:04:31

larand54
Replies: 3

Having problem finding out how I should handle INSERT of objects that contains linked classes.
ORMAdd does not seems to handle that.
I came up with an own solution but don't really like it.

The main TSQLRecord looks like this:

     TSQLRecordCustomer = class(TSQLRecord)
  protected
    fContact: TSQLRecordPersonContactable;    <<<--- The linked class
  published
    property Contact: TSQLRecordPersonContactable read fContact write fContact;

   
The repositorys add-function:   

function TCustomerRepository.Add(const aAggregate: TCustomer): TCQRSResult;
var
  rest: TSQLRest;
  SQLpc: TSQLRecordPersonContactable;
  pc: TPersonContactable;
  SQLcus: TSQLRecordCustomer;
begin
  result := cqrsInternalError;
  rest := GetRest(self);
  SQLpc := TSQLRecordPersonContactable.Create;
  SQLcus := TSQLRecordCustomer.Create;
  CustomerToRecord(aAggregate,SQLcus,SQLpc); <<<---- Copies all fields from TCustomer into SQLcus and SQLpc
  SQLcus.Contact := TSQLRecordPersonContactable(rest.add(SQLpc, true));
  rest.Add(SQLcus, true);
  result := cqrsSuccess;

This works but I don't know how to handle different errors here and the "CustomerToRecord" function is heavy to type.

What I want is that this should be enough.

  Result := ORMAdd(aAggregate);

But this leaves the "Contact"-field equal to zero.

I'm afraid that it isn't possible using ORM this way but hopes for a simpler and better solution than mine.

#91 Re: mORMot 1 » ORMSelectAll('Name_Last LIKE ?',[aName+'%'],(aName='')) does not work » 2020-04-12 11:49:19

You are right, it works when running using external tables, at least against SQLite3.
Thank's for the help!
But isn't this a limit to this framework? I've thought that it should be transparent to any storage? Or am I wrong?

#92 mORMot 1 » ORMSelectAll('Name_Last LIKE ?',[aName+'%'],(aName='')) does not work » 2020-04-12 09:45:02

larand54
Replies: 4

I run the regressiontest of TUser in the DDDExample but found that there was no test with the 'LIKE' operator.
The function "SelectByLastName" exists though and it takes an extra boolean parameter "StartsWith" that controls whether you want exact(false) or something that starts with..
Added some code that exercise that function.

    test.Check(Rest.Services.Resolve(IDomUserCommand,cmd));
    CQRS := cmd.SelectByLastName('Last1', false);                  // Exact - this one works
    CQRS := cmd.SelectByLastName('Last', True);                    // Using "LIKE" and will not find anything.

Tried with debugging and finally entering: function TSQLRestStorageInMemory.GetJSONValues
where it checked the type of operator used.
Following cleaned code shows the execution flow..

function TSQLRestStorageInMemory.GetJSONValues(Stream: TStream;
    case Stmt.Where[0].Operator of
    opEqualTo:
opIsNull, opIsNotNull:
    else begin
err:  W.CancelAll;
      result := 0;
      exit;

When using the "LIKE" operator, the value of "Stmt.Where[0].Operator" is "opLike" and there's no entry for that and that causes this select to end with "W.CancelAll".

What's wrong here? Shouldn't it be an entry for "opLike".

#93 mORMot 1 » Inheritance and persistance don’t work as I expected » 2020-03-30 17:06:15

larand54
Replies: 0

I tested using the dddUserTypes unit with the classes TPersonFullName, TPerson and TPersonContactable.
Instead of Tuser I created the TCustomer class that inherits from TsynAutoCreateFields and contains a field of type TPersonContactable.

  TCustomer = class(TSynAutoCreateFields)
  private
    fContact: TPersonContactable;
  published
    property Contact: TPersonContactable read fContact;
  end;

Calling –
TDDDRepositoryRestFactory.ComputeSQLRecord([TPersonContactable, TCustomer]);
creates the following classes:
•    TSQLRecordPerson
•    TSQLRecordPersonContactable
•    TSQLRecordCustomer

Calling - .CreateMissingTables creates the following tables:
•    PersonContactable
•    Customer
PersonContactable contains all the fields from TAddress, TPerson and TPersonFullName and it’s own.
Regression tests on TCustomer confirm access to all fields of these classes.
But testing using ORM doesn’t give access to the fields in the class TPersonFullName. There is no error or warnings when adding records But the fields Name_First, Name_Middle, and Name_Last will not be updated in the table  “PersonContactable” but all other fields are updated.
I’ve checked all I can think of but can not make this work. Strange that ORM creates the fields from TPerson-TPersonFullName but does not allow access to the fields from TPersonFullName.
I wonder what I may be missing, I’m sure this should work automatically if I did everything wright.
Hope anyone could spread some light over this.

#94 Re: mORMot 1 » fields of type currency is not persisted » 2020-03-16 13:15:32

You are completely right, but it makes "currency" special any way as it works if you do: TPrice = double;
Thank's a lot!

#95 mORMot 1 » fields of type currency is not persisted » 2020-03-16 10:23:29

larand54
Replies: 3

In my little test project running some regression tests, I found that fields that have the type "currency" will not be updated on the database.
I thought it should work with "currency" but in my case apparently not. If I change type "TPrice" to be of type "double" it works.
Am I doing something wrong or should I avoid type "currency"?

---- A crippled piece of the code i use  ----

type
  TPrice                    = type currency;
  TDiscount                 = type double;
  TWeight                   = type double;
-------------------------------------------------

  TSQLRecordProduct = class(TSQLRecord)
  protected
    fweight: double; // TWeight
    fdiscount: currency; // TDiscount
    fPrice: double;//currency; // TPrice
  published
    property weight: double read fweight write fweight;
    property discount: double read fdiscount write fdiscount;
    property price: double read fPrice write fPrice;
  end;
--------------------------------------------------
  TProduct = class(TSynAutoCreateFields)
  private
    fWeight: TWeight;
    fPrice: TPrice;
    fDiscount: TDiscount;
  public
    constructor create(const aName: TProductName; const aWeight: TWeight; const aPrice: TPrice;
                       const aDiscount: TDiscount); overload;
  published
    property weight: TWeight read fWeight write fWeight;
    property price: TPrice read fPrice write fPrice;
    property discount: TDiscount read fDiscount write fDiscount;
  end;
    TProductObjArray = array of TProduct;
   
------------- part of server code --------
RestServer := TSQLRestExternalDBCreate( TSQLModel.Create([TSQLRecordProduct]),
RestServer.ServiceContainer.InjectResolver([TProductRepoFactory.Create(RestServer)],true);
   
---------------------- Test code below --------------------
var p1: TProduct;

p1 := TProduct.Create;
p1.weight := 12.3;
p1.price :=  249.99;
p1.discount := 25;
aCQRSRes := cmd.Add(p1);
Check(cqrsSuccess = aCQRSRes);
Check(cqrsSuccess = cmd.Commit);

p1.price is not persisted.

#96 mORMot 1 » ObjectToJSON and stored AS_UNIQUE » 2020-02-07 12:08:46

larand54
Replies: 1

A few problems I've stumbled into:

1. When using "stored AS_UNIQUE" or a calculated property like "discountedprice" below, those properties is lost using ObjectToJSON.
   Why? and what can I do about it?
   
2. Why do I get the new function: "function AS_UNIQUE" when I press (ctrl-shift C)?
   Is it possible to avoid?
   
Below a sample code:
  TProduct = class(TSynAutoCreateFields)
  private
    fName: TProductName;
    fPrice: TPrice;
    fDiscount: TDiscount;
    function getDiscountedPrice: TPrice;
    function AS_UNIQUE: Boolean;                            <<<<----- Will be automatically created on (ctrl-shift C)
  public
    constructor create(const aName: TProductName; const aPrice: TPrice;
                       const aDiscount: TDiscount); overload;
    class procedure RegressionTests(test: TSynTestCase);
  published
    property productName: TProductName index 80 read fName stored AS_UNIQUE;
    property price: TPrice read fPrice write fPrice;
    property discount: TDiscount read fDiscount write fDiscount;
    property discountedPrice: TPrice read getDiscountedPrice;
  end;

============
procedure T
var b,c: TProduct;
    jsonC, jsonB: RawUTF8;
begin
  c := TProduct.Create('HardDrive 2TB',12.5,5.0);
  with test do
  try
    jsonC := ObjectToJSON(c)+'*';
---->>>>  jsonC will not contain productName nor discountedPrice.

#97 mORMot 1 » Legacy tables and the ID-field » 2019-11-19 05:48:04

larand54
Replies: 1

We have a huge system containing several hundreds of tables and I tries to replace pieces of delphi-code by using mORMot and the DDD-concept.
When I do some testing I find that it won't work when the tables don't contain the ID-field. Which is true in most tables.

I can not access these tables without getting the "Invalid column name 'ID'" - error
In the implementation of the service I'm intend not to use ORM on these tables to avoid such problems. But that's not enough.

Even the call of "CreateMissingTables" returns this error. So I wonder if there is a solution for this or if I need to treat these tables in a total different way?

#98 Re: mORMot 1 » Checking against NULL data from DB » 2019-06-11 15:46:44

That was a good idea, that worked! Normally I like to use standard ORM-style instead of plain SQL but sometimes it seems to be necessary to breake that rule.
If someone have a better idea using ORM you're welcome, but otherwise I would say this is now solved.
Thank's smile

#99 Re: mORMot 1 » Checking against NULL data from DB » 2019-06-10 16:29:25

Yes I have read that and made all TDateTime fields of type TNullable. But it didn't help.
You see, I'm new to mORMot and not so familiar with variants. I have not so easy to understand how I should use it here.

I doubt that I can write the code like I did in my example above even though it feels natural for me as I'm more used to SQL.

I just test mORMot occasionally when I have time. I'm looking for a way to use it in a larger project and try to find as many pitfalls as possible before I proceeds with a larger project.
I've found a lot of them already and some of them are solved but this problem are still unsolved.

#100 mORMot 1 » Checking against NULL data from DB » 2019-06-10 09:49:15

larand54
Replies: 5

Using ORM I want to check if a field is null or not like this:

function TInfraRepoTicket.SelectUO: TCQRSResult;
begin
  result := ORMSelectAll('DateOpened is ?',[null]);
end;

This doesn't seem to work as I never get a hit.
How can I solve this problem?

Board footer

Powered by FluxBB