#51 Re: mORMot 1 » changed properties » 2014-06-10 08:38:03

A global "content history" would be awesome. And if that's stored in a separate table, one could store the history in a separate DB easily by using virtual external tables... so it doesn't fill up your main db. Great.

#52 Re: mORMot 1 » Save huge file-stream (considered about 2GB) in a Table as BLOB. » 2014-06-09 08:26:22

I agree with MichaelR. I have seen people putting db backup files in the very same db... (not for a long time of course ;-) )
If a system allows for such things, people will do.
You really should have a rather good reason if you want to put such big files in a db otherwise they should be stored elsewhere.

#53 Re: mORMot 1 » mORMot with Delphi XE6 REST mobile client » 2014-06-06 09:48:57

After running the server as administrator once, you can run it as normal user

#55 Re: mORMot 1 » Automatic JSON serialization of record via Enhanced RTTI » 2014-06-05 08:50:32

The exact concern is schema evolution.

I am using XE5 and nightly build (may be 3-5 days old) and dynamic arrays and records are still binary in db fields and not JSON. I can make them to serialize to JSON but then I have to write custom serialization code or at minimum have to register my record types ...

To circumvent that I could also use a RawJSON property in a TSQLRecord and manually serialize / deserialize with RecordSaveJSON/RecordLoadJSON but that wrapping is all extra flights which I thought I could circumvent if I just could set an option 'somewhere' to tell mormot to use json instead of binary format.
E.g. one could use the storage parameter for DynArray or Record properties and introduce a storage binary and storage json ...

and maybe that only works with newer delphi versions, the older ones could continue to use binary format...

#56 Re: mORMot 1 » Automatic JSON serialization of record via Enhanced RTTI » 2014-06-05 08:31:14

Hi,

ab, if you're going to extend on this topic, I also have a feature request...

Dynamic arrays and Records are serialized into binary format when they're published properties of any TSQLRecord descendant when that's stored in a db. That's fine and is working nicely. But, when time comes one might have to extend a type and then the already stored records in the db are no longer compatible to the new record type and can't be deseriealized any more to the new version of that type - which is understandable...

While e.g. TDocVariants are serialized into json in a db record field, (since those don't have an explicit structure), you can simply introduce new fields in such types. But here I don't have compile time type checking of course.

For me ( and maybe others... ? ) it would be of great help if it were possible to have a global or per TSQLRecord or per Field configuration option for record and dynarray serialization in public properties of TSQLRecord descendants.That option should force serialization in json format instead of binary format. Then deserializing such record would be possible even if the type of the record has changed. (Like it is possible by manual calling RecordLoadJSON and using the soReadIgnoreUnknownFields option). My main point here is not the serialization format but the possibility for schema evolution and I think going for JSON format would be the easiest way...
Of course I could define custom serialization formats per record but this leads to a lot of handwriting which potentially can be done automatically. And since your enhanced usage of RTTI for 2010++ versions of Delphi I started to throw out all of the record registration calls... wink

Also I could use TCollection/TCollectionItem descendants as a record alternative everywhere. Sometimes that makes sense, sometimes not. DynArrays/Records often make more sense. I just have the problem that when Record Types change, then I have do convert existing DB-Content before it's usable with the changed Record Type.

What do you think?

Martin

#57 Re: mORMot 1 » How to get IP-Addr. of caller of an Interface based service method » 2014-05-30 19:27:08

solved....

just found out that if I use the IP-Address instead of 'localhost' while creating the client, everything works like expected and I can see the REMOTEIP

smile

#58 Re: mORMot 1 » How to get IP-Addr. of caller of an Interface based service method » 2014-05-29 14:52:06

I am using the latest nightly build and register the server with the following code:

    fServer := TSQLRestServerDB.Create(FModel, ChangeFileExt(paramstr(0), '.db3'),True);
    fServer.CreateMissingTables;
    fServer.ServiceRegister(TAuftragsbearbeitung,[TypeInfo(IFuseAuftragsbearbeitung)],sicSingle);
    fHTTPServer := TSQLHttpServer.Create(PORT_NAME,[fServer],'+',useHttpApiRegisteringURI);

The client is created as follows:

  fClient := TSQLHttpClient.Create('localhost', PORT_NAME, FModel);
  fClient.SetUser('User', 'synopse');
  fClient.ServiceRegister([TypeInfo(IFuseAuftragsbearbeitung)], sicSingle);

#59 Re: mORMot 1 » How to get IP-Addr. of caller of an Interface based service method » 2014-05-29 12:07:37

well, in my case that returns an empty RawUTF8
(XE5, Win8.1)

and InHead contains:
'Cache-Control: no-cache'#$D#$A'Connection: Keep-Alive'#$D#$A'Pragma: no-cache'#$D#$A'Content-Length: 3'#$D#$A'Content-Type: application/json; charset=UTF-8'#$D#$A'Accept: */*'#$D#$A'Accept-Encoding: synlz'#$D#$A'Host: localhost:888'#$D#$A'User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows; Synopse mORMot 1.18 TWinHTTP)'#$D#$A'ConnectionID: FD00000060000009'#$D#$A

#60 mORMot 1 » How to get IP-Addr. of caller of an Interface based service method » 2014-05-29 09:12:55

martin.suer
Replies: 12

Hi,

in an interface based service method I can access the ServiceContext with the Request and the Factory. I can get access to all sort of information, however I haven't found out how to get the IP-Address of the caller of the method.

Is that possible?

Martin

#61 Re: mORMot 1 » Bug in TSQLRecord.FillRow when TSQLRecord contains a TDocVariant » 2014-04-15 10:57:40

Ok, the reason is that the Fill method changes the content of the internal TSQLTable (while the Variant content is parsed). So any record can only be filled once.

A change in mormot.pas will fix the immediate problem:

procedure TSQLPropInfoRTTIVariant.SetValue(Instance: TObject; Value: PUTF8Char;
  wasString: boolean);
var V: Variant;
    ValueCopy: RawUTF8;
begin
  ValueCopy:=Value;
  GetVariantFromJSON(@ValueCopy[1],wasString,V,@DocVariantOptions);
  SetVariantProp(Instance,pointer(fPropInfo),V);
end;

but I am not sure if this a) is the right place, b) will introduce side effects.
And of course it will decrease performance (not significantly though), since the string will be copied here.

What about other serialized types (e.g. records)? Does the same problem exist there too?

Thoughts?

#62 mORMot 1 » Bug in TSQLRecord.FillRow when TSQLRecord contains a TDocVariant » 2014-04-14 20:18:23

martin.suer
Replies: 2

Hi ab,

I am using XE5 and the nightly build.

Code to reproduce:

program VariantBug;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  SynCommons,
  mORMot,
  mORMotSqlite3,
  SynSQLite3Static;

type
  TSQLRecordData = class(TSQLRecord)
  private
    fName: RawUTF8;
    fData: variant;
  public
  published
    property Name: RawUTF8 read fName write fName stored AS_UNIQUE;
    property Data: variant read fData write fData;
  end;

var
  Model : TSQLModel;
  DB : TSQLRest;
  aRec: TSQLRecordData;
  aID: integer;
begin
  DeleteFile('bug.db3');
  Model := TSQLModel.Create([TSQLRecordData]);
  DB := TSQLRestServerDB.Create(Model, 'bug.db3');
  TSQLRestServerDB(DB).CreateMissingTables(0);

  aRec := TSQLRecordData.Create;
  aRec.Name := 'Joe';
  aRec.Data := _ObjFast(['name','Joe','age',30]);
  aID := DB.Add(aRec,True);
  aRec.Free;

  aRec := TSQLRecordData.Create;
  aRec.Name := 'Jon';
  aRec.Data := _ObjFast(['name','Jon','age',31]);
  aID := DB.Add(aRec,True);
  aRec.Free;

  aRec := TSQLRecordData.Create;
  aRec.Name := 'Joan';
  aRec.Data := _ObjFast(['name','Joan','age',29]);
  aID := DB.Add(aRec,True);
  aRec.Free;

  aRec := TSQLRecordData.CreateAndFillPrepare(DB,'');
  aRec.FillOne;
  WriteLn(aRec.Data.Name, ' (',aRec.Data.age,')');
  aRec.FillOne;
  WriteLn(aRec.Data.Name, ' (',aRec.Data.age,')');

  aRec.FillRow(1);
  WriteLn(aRec.Data.Name, ' (',aRec.Data.age,')'); // <== Exception
  // because aRec.Data is unassigned here

  aRec.Free;
  ReadLn;
end.

without the Data property in the TSQLRecord, the FillRow Method is working correctly.

Is this a limitation or a bug?

Martin

#63 Re: mORMot 1 » Enhanced and fixed late-binding of variants for Delphi XE2 and up » 2014-03-29 15:59:37

This is great, I have seen that symptom yesterday but you're fixing issues before one is reporting it ... :-)

#64 mORMot 1 » Record Serialization of records that contain multiple dynamic arrays » 2014-03-29 15:48:38

martin.suer
Replies: 1

Hi again,

maybe there's an issue with record serialization when a record contains multiple different dynamic arrays like in the code example below.

type
  TSubAB = packed record
    a : RawUTF8;
    b : integer;
  end;
  TSubCD = packed record
    c : byte;
    d : RawUTF8;
  end;
  TAggregate = packed record
    abArr : array of TSubAB;
    cdArr : array of TSubCD;
  end;
const
  __TSubAB = 'a : RawUTF8; b : integer;';
  __TSubCD = 'c : byte; d : RawUTF8;';
  __TAggregate = 'abArr : array of TSubAB; cdArr : array of TSubCD;';
var
  ab0,ab1: TSubAB;
  cd0,cd1,cd2: TSubCD;
  agg,agg2: TAggregate;
  u,v,w : RawUTF8;
begin
  TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TSubAB),__TSubAB);
  TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TSubCD),__TSubCD);
  TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TAggregate),__TAggregate);

  ab0.a := 'AB0';
  ab0.b := 0;
  ab1.a := 'AB1';
  ab1.b := 1;
  cd0.c := 0;
  cd0.d := 'CD0';
  cd1.c := 1;
  cd1.d := 'CD1';
  cd2.c := 2;
  cd2.d := 'CD2';
  SetLength(agg.abArr,2);
  agg.abArr[0] := ab0;
  agg.abArr[1] := ab1;
  SetLength(agg.cdArr,3);
  agg.cdArr[0] := cd0;
  agg.cdArr[1] := cd1;
  agg.cdArr[2] := cd2;

  u := RecordSaveJSON(agg,TypeInfo(TAggregate));
  w := u;
  RecordLoadJSON(agg2,@u[1],TypeInfo(TAggregate));
  v := RecordSaveJSON(agg2,TypeInfo(TAggregate));

  Writeln ('w = ',UTF8ToString(w));
  Writeln ('v = ',UTF8ToString(v));

That code creates a record, serializes it to JSON, then deserializes it to a new record. Both records should then contain the same values but don't.

The second dynamic array in the TAggregate record gets lost...

Output of the above code:

w = {"abArr":[{"a":"AB0","b":0},{"a":"AB1","b":1}],"cdArr":[{"c":0,"d":"CD0"},{"c":1,"d":"CD1"},{"c":2,"d":"CD2"}]}
v = {"abArr":[{"a":"AB0","b":0},{"a":"AB1","b":1}],"cdArr":[]}

Is this an issue or am I doing sth. wrong ?

Martin

#65 Re: mORMot 1 » TSQLRecord with Record Properties that contain Strings » 2014-03-29 09:52:38

Ok, scratch the above...

I figured it's as easy as one is used to with mORMot ;-)

Calling RegisterCustomRTTIRecordProperty like this:

Props.RegisterCustomRTTIRecordProperty(self, TypeInfo(TVOAddress), 'Address', @TSQLCustomer(nil).FAddress);

does the job.

Thanks for this great framework!

Martin

#66 mORMot 1 » TSQLRecord with Record Properties that contain Strings » 2014-03-28 20:33:29

martin.suer
Replies: 2

Hi Arnaud,

in chapter 5.1.7 (Record Fields) of the documentation it's written:

"You may call Props.RegisterCustomRTTIRecordProperty() for a record containing reference-counted fields like string, variant or nested dynamic arrays."

Do you have an example of how to use that method?

The example with the TGUID in that chapter is working. As soon as I try to adapt that concept to a record that contains a RawUTF8 field or a dynamic array, it stops working (as expected because it's described in the documentation). But I can't figure out how to use the RegisterCustomRTTIRecordProperty method to make it work...

Martin

#67 Re: mORMot 1 » Smart Mobile Studio mORMot class server » 2014-03-22 15:32:00

Hi,

is the archive in the dropbox mentioned in this thread the latest version of the mORMot/SmartMS-Integration?
Since I can't find it in the mORMot nightly 1.18 build, is it "officially" part of mORMot or not?

With that and Smart 2.0.1 I can access the ORM but have troubles using Interfaced Server.

Martin

#68 Re: mORMot 1 » SmartMS 2.0.0.273 breaks authentication » 2014-03-20 09:32:49

SmartMS 2.0.1 build 741 has been released on 18.03.2014. Don't know yet if that fixes the problem...

#69 Re: mORMot 1 » SmartMS 2.0.0.273 breaks authentication » 2014-03-07 16:13:17

Hi ab,

which version of sms (professional or enterprise) do I want to order if I want to use it with mORMot (and no other backend ) ?
(after the mentioned fix is released by them)

Martin

#70 Re: mORMot 1 » TSQLRecord String Properties » 2014-01-03 13:38:34

Thank you, great. That gives me enough reason to use RawUTF8 wink

#71 mORMot 1 » TSQLRecord String Properties » 2014-01-03 12:18:59

martin.suer
Replies: 2

Hi,

from the Docs I can see that RawUTF8 (Unicode Strings encoded in AnsiString) is the preferred Type for String properties in TSQLRecord Descendants. As a Delphi XE5 user, are  there any downsides if I just use String as the Type for String properties when I don't need to be compatible with older versions of Delphi?

Thanks
Martin

#72 mORMot 1 » Zeos 7.2 with Firebird 2.5.2 on external server » 2013-12-25 11:01:40

martin.suer
Replies: 2

Hi,

the answer to my question about UniDAC with external Firebird with the performance comparison to zeos made me curious. So I downloaded the zeos trunc and began experimenting...

I now have zeos 7.2 trunc running with mormot. It generally works but I ran into two issues:

1) is the same I ran into using UniDAC: The momrot code is assuming one uses the embedded Firebird (there's no way to pass a ServerName to the URI function). I can setup a connection to an external Firebird db using this code:

aProps := TSQLDBZeosConnectionProperties.Create(
    TSQLDBZEOSConnectionProperties.URI(dFirebird),
    'mormot', 'SYSDBA', 'masterkey');
  TSQLDBZeosConnectionProperties(aProps).ZeosURL.HostName := '10.211.55.2';
  TSQLDBZeosConnectionProperties(aProps).ZeosURL.LibLocation :=
    'C:\works\Firebird-2.5.2.26540-0_Win32\bin\fbclient.dll';
  TSQLDBZeosConnectionProperties(aProps).ZeosURL.Properties
    .Values['createNewDatabase'] := '';

This works but one has to change the ZeosURL manually after creating the ConnectionProperties. Also the TSQLDBZeosConnectionProperties.Create is setting the createNewDatabase because it tries to find the database (which in my case is on a different server) on the local servers file system. If I don't reset that value, zeos tries to delete my existing db on the external server...

2) Using the mORMot Sample Project 02 (modified to use Firebird with   VirtualTableExternalRegister(Form1.Model,TSQLSampleRecord,aProps,'SampleRecord') ) there's a problem with setting the entered Values in the form to the query parameters.
I have changed the TSQLSampleRecord and renamed the Time property because that's a firebird reserved word. With that and the above setup code for the zeos connection the Sample Project02 creates a SAMPLERECORD Table in the firebird db with 2 blob fields (because the corresponding two properties in the TSQLSampleRecord have no index clause). When I enter values to the form and press the 'Add the message' button, a new record is saved to the db but the 2 fields for NAME and MESSAGE are empty.
Is this an expected behaviour?
Changing the code of the sample to use UniDAC instead of zeos, writing the NAME and MESSAGE fields to the blob fields is working. So at least the behaviour is different.
Modifying the TSQLSampleRecord definition by adding index clauses to the RawUTF8 properties, zeos creates the Table like expected with the corresponding varchar db fields with the expected length and then the Sample Project02 is working correctly also with zeos.
Of course, I wouldn't omit the index clause in real life projects but am wondering if there may be a general problem with setting blob values using mORMot, with zeos and firebird and wanted to let you know.

Martin

#73 Re: mORMot 1 » OFF-TOPIC: Merry christmas... » 2013-12-25 10:22:20

Fröhliche Weihnachten. Alles Gute für das neue Jahr!

#75 mORMot 1 » SynDBUniDAC TSQLDBUniDACConnectionProperties constructor parameter » 2013-12-21 21:09:25

martin.suer
Replies: 2

Hi,

I want to use the UniDAC library for firebird access.

In the constructor of the class TSQLDBUniDACConnectionProperties

Create(const aServerName, aDatabaseName, aUserID, aPassWord: RawUTF8);

 
mormot really is using the first parameter aServerName for what UniDAC names their provider (e.g. Oracle, Interbase, etc).

Due to that, I have no means to pass a server name to be used with firebird. Mormots implementation only works with embedded Firebird but not with Firebird on a different DB-Server.
Looking at the code I can see that in TSQLDBUniDACConnection.Create either fDatabase.Database or fDatabase.Server is set (depending on the DBMS) but not both.

Using Firebird on an external server requires to set both.

For the moment I can help myself by changing the TSQLDBUniDACConnection.Create by adding these two lines at the end:

if fDatabase.SpecificOptions.Values['Server']<>'' then
    fDatabase.Server := fDatabase.SpecificOptions.Values['Server'];

Then I can create my TSQLDBUniDACConnectionProperties this way:

aProps := TSQLDBUniDACConnectionProperties.Create(
    'Interbase',
    'mormot',
    'SYSDBA', 'masterkey');
  aProps.SpecificOptions.Values['Server'] := '10.211.55.2';

But I think this should only be a temporary workaround.
Mormot should change the TSQLDBUniDACConnectionProperties constructor by adding a provider parameter instead of using the aServerName parameter for it.

What do you think?

Martin

#76 Re: mORMot 1 » Migrate table by hand » 2013-12-15 12:36:53

Hi,

I think this is some kind of a more general topic.
Are there best practices about how to change an existing model?
I understand it's easy to add new TSQLRecord descendants and extend a model that way.

But when I need to add an additional property to an existing TSQLRecord descendant and at the same time want to continue using the already existing underlying db, how do I do that?

The same problem arises if I want to change a property name... or a Class name of a TSQLRecord descendant.

If I decide to write a migration program that could convert an existing model to a newer version of that model, other problems arise:
I can not have different versions of a model at the same time in the same program which would be necessary to read from the existing db and write to the converted db.

I am asking for the best general aproach of how to do such evolutionary conversions. Since changing a model without loosing existing data is a common scenario, how have you dealt with that in your own projects?

Changing the db manually? Would be possible I guess, but that would somehow be a real break of the ORM Idea. Is there some kind of way doing it in object pascal code? Spending quite some time with the documentation and the forum I haven't yet found anything specific to this topic.

kind regards
Martin

Board footer

Powered by FluxBB