You are not logged in.
Pages: 1
I download branch:master from https://github.com/synopse/mORMot today, When I compile with Delphi XE2 WIN32, it show follow error:
D:\Delphi\Packages\mORMot\Source\SQLite3\Samples\27 - CrossPlatform Clients>"C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\dcc32.exe" RegressionTests.dpr -B -Q -GD -OD:\Delphi\Packages\mORM
Embarcadero Delphi for Win32 compiler version 23.0
Copyright (c) 1983,2011 Embarcadero Technologies, Inc.
D:\Delphi\Packages\mORMot\Source\crossplatform\SynCrossPlatformREST.pas(2285) Error: E2568 Can't create new instance without CONSTRUCTOR constraint in type parameter declaration
RegressionTests.dpr(184) Fatal: F2063 Could not compile used unit 'SynCrossPlatformREST.pas'
How to fix it?
I use unidac, on the server side, I set as follow:
function CreateConnection(dbConfig: TDatabaseConfig): TSQLDBUniDACConnectionProperties;
begin
Result := TSQLDBUniDACConnectionProperties.Create('MySQL',dbConfig.Name, dbConfig.Username,dbConfig.Password );
Result.SpecificOptions.Values['Server'] := dbConfig.Address;
Result.SpecificOptions.Values['Port'] := IntToStr(dbConfig.Port);
(Result.MainConnection as TSQLDBUniDACConnection).Database.LoginPrompt := false;
end;
So, there is not login prompt dialog when I run server, but it still popup login prompt dialog when I run client side, the code as follow:
fModel := TSQLModel.Create([TRoute,TTrip],RESTRestRootName);
fClient := TSQLHttpClientWinHTTP.Create(AppConfig.Server, AppConfig.Port, fModel);
How can I solve this ? thanks!
@ab
I just find you answer, thank you.
I create follow procedure:
procedure TableSort(table:TSQLTable; const FieldNames: array of RawUTF8);
var
i,n: Integer;
intptrs: array of PInteger;
indexes: array of Integer;
orders: array of boolean;
begin
n := Length(fieldNames);
SetLength(intptrs,n);
SetLength(orders,n);
SetLength(indexes,n);
for i := Low(intptrs) to High(intptrs) do
begin
intptrs[i] := @indexes[i];
orders[i] := True; //ASC
end;
table.FieldIndex(fieldNames,intptrs);
table.SortFields(indexes,orders);
end;
and call it like this:
resource := TResource.CreateAndFillPrepare(Client, EmptyStr, []);
TableSort(resource.FillTable,['path','operation']);
It return result same as 'order by path,operation' but not sam as 'order by convert(path using gbk),convert(operation using gbk)';
Must I write a interface-based service to implement my sorting ?
I use CreateAndFillPrepare to query mysql, and I specified the order by clause like this:
resource := TResource.CreateAndFillPrepare(Client, 'order by convert(path using gbk),convert(operation using gbk)', []);
But the server report:
ESQLite3Exception {"ErrorCode":1,"SQLite3ErrorCode":2,"Message":"Error SQLITE_ERROR (1) [SELECT ID,path,operation,version FROM Resource order by convert(path using gbk),convert(operation using gbk)] using 3.13.0 - near \"using\": syntax error, extended_errcode=1"}
but I can run the sql in mysql correctly:
SELECT ID,path,operation,version FROM Resource order by convert(path using gbk),convert(operation using gbk)
Is there a way to pass the complex order by clause to mysql ? Thanks a lot.
I use follow code create mORMot auth table in mairab 5.5.50 database:
fConn := TODBCConnectionProperties.Create('',RawUTF8(connectionString), '', '');
fModel := TSQLModel.Create([TSQLAuthGroup,TSQLAuthUser, ...]);
VirtualTableExternalMap(fModel, TSQLAuthGroup, fConn, 'mormot_auth_group');
VirtualTableExternalMap(fModel, TSQLAuthUser, fConn, 'mormot_auth_user');
fRestServer := TSQLRestServerDB.Create(fModel, ':memory:', False); // authentication=false
fRestServer.AuthenticationRegister(TSQLRestServerAuthenticationDefault);
fRestServer.CreateMissingTables;
When I run these code, it create AuthGroup,AuthUser table correctly, but the log report error:
ESQLite3Exception {"ErrorCode":1,"SQLite3ErrorCode":2,"Message":"Error SQLITE_ERROR (1) [SELECT RowID FROM AuthUser LIMIT 1] using 3.13.0 - no such table: AuthUser, extended_errcode=1"} at 006A4D6E stack trace API 005E4350 005E4378
The C/S application can work fine, and the mORMot default groups, users created correctly. I drop the mormot_auth_group,mormot_auth_user, run again, the error still reported! I change the code:
VirtualTableExternalMap(fModel, TSQLAuthGroup, fConn, 'AuthGroup');
VirtualTableExternalMap(fModel, TSQLAuthUser, fConn, 'AuthUser');
Nothing help ,but the error .
What's wrong with my codes? any clue? thanks lots !
Thank ab! sharding or aggregate pattern, it is more complicated, I could expense some time to understand it.
TTourist = class(TSQLRecord)
private
fSchedule: TSchedule;
published
property schedule: TSchedule read fSchedule write fSchedule;
end;
TSchedule = class(TSQLRecord)
private
fDepartureDate: TDateTime;
fBus: TBus;
published
property bus : TBus read fBus write fBus;
end;
TBus = class(TSQLRecord)
private
fLicense: RawUTF8;
published
property license : RawUTF8 read fLicense write fLicense;
end;
When I call
tourist := TTourist.CreateAndFillPrepareJoined(Client,
'schedule.DepartureDate>=? and schedule.DepartureDate<=?',
[],
[dateS1,dateS2]);
the tourist record is loaded,which include schedule,bus bus is nil in schedule. how can I load all associate object, then I can access the sub object:
tourist.schedule.bus.license;
thank for any clue!
I found the result in
https://tamingthemormot.wordpress.com/2 … tionships/
thanks Taming the mORMot!
@edwinsn
I find out the docs: TSQLRest.Add , but the ForceID is not for associated instance,but the main instance, as the doc said:
if ForceID is true, client sends the Value.ID field to use this ID for adding the record (instead of a database-generated ID)
In Delphi debug state, I can find out:
schedule -> fRoute -> TSQLRecord -> fID = 2
And the Id = 2 TRoute record actually in table bt_route.
I use Client.Add(schedule,true, true); but the route id still incorrect. and I could not find the TSQLHttpClientWinHTTP.Add API doucment online or in synopse's PDF.
I define two class as follow:
TRoute = class(TSQLRecord)
private
fRouteNumber: string;
...
published
property routeNumber: string read fRouteNumber write fRouteNumber;
...
end;
TSchedule = class(TSQLRecord)
private
fRoute: TRoute;
...
published
property route: TRoute read fRoute write fRoute;
...
end;
TSchedule include TRoute's ID, now I want to save a TSchedule instance, and it's routeId is correct:
procedure TMyForm.btnOKClick(Sender: TObject);
var
schedule: TSchedule;
Id: Integer;
begin
schedule := TSchedule.Create(Client, StrToInt(txtId.Text));
try
schedule.route := TRoute.Create(Client, fRouteId);
...
Id := Client.Add(schedule, true);
finally
schedule.Free;
end;
end;
When the Client.Add execute, the database table has the route id 24670096, not the correct value 2, what wrong with me?
Is this pseudo code correct ?
model := TSQLModel.Create([TOrganization,TEmployee,TRoute...],RESTRestRootName );
VirtualTableExternalMap(model, TOrganization, Conn, 'sys_organization').MapField...;
VirtualTableExternalMap(model, TEmployee,Conn, 'hr_employee').MapField...;
VirtualTableExternalMap(model, TRoute,Conn, 'tour_route').MapField...;
restServer := TSQLRestServerDB.Create(model, ':memory:', False);
restServer.CreateMissingTables;
fHttpServer := TSQLHttpServer.Create(fListenPort, [restServer], '+', useHttpApiRegisteringURI);
so I can only use just one RESTRestRootName .
I have 8 TSQLRecord class, I want use TSQLModel.Create once with just one RESTRestRootName, but I am a newbie on mORMot, I found the VirtualTableExternalRegisterAll can not specify external table name, so I have to use VirtualTableExternalMap, this lead to duplicate code, and I don't know how to specify REST URI root name in TSQLModel.Create([....], REST_URI_ROOT_NAME) just only once, please help me,thanks a lot.
unit uORM;
interface
uses
Classes, SynCommons, mORMot,SynLog, mORMotSQLite3, mORMotHttpClient,mORMotDB, mORMotHttpServer, SynDB,
SynDBODBC;
type
TRestServers = array of TSQLRestServer;
TOrganization = class(TSQLRecord)
private
fName:String;
fType:String;
fParent: TOrganization;
fParentIds:String;
fWeight:Integer;
fEnabled:Boolean;
fMemo:String;
published
property name: string read fName write fName;
property typ: string read fType write fType;
property Parent: TOrganization read fParent write fParent;
property parentIds: string read fParentIds write fParentIds;
property weight: integer read fWeight write fWeight;
property isEnabled: boolean read fEnabled write fEnabled;
property memo: string read fMemo write fMemo;
end;
TNationality = class(TSQLRecord)
private
fName:String;
fCode:String;
published
property name:String read fName write fName;
property code:String read fCode write fCode;
end;
TEmployeePost = class(TSQLRecord)
private
fName:String;
published
property name:String read fName write fName;
end;
TEmployeeCategory = class(TSQLRecord)
private
fName:String;
fFlag:Byte;
published
property name:String read fName write fName;
property flag:Byte read fFlag write fFlag;
end;
TEmployee = class(TSQLRecord)
private
fName:string;
fCode:string;
fOrganization:TOrganization;
fIdCard:string;
fGender:boolean;
fBirthday:TDatetime;
fAddress:String;
fNationality:String;
fMobilePhone:String;
fGeneralPhone:String;
fOfficePhone:String;
fHomePhone:String;
fEmail:String;
fQQNumber:String;
fCategory:TEmployeeCategory;
fPost:TEmployeePost;
fBankName:String;
fBankAccount:String;
fDeleted:Boolean;
fMemo:String;
published
property name:string read fName write fName;
property code:string read fCode write fCode;
property organization:TOrganization read fOrganization write fOrganization;
property idCard:string read fIdCard write fIdCard;
property gender:boolean read fGender write fGender;
property birthday:TDatetime read fBirthday write fBirthday;
property address:String read fAddress write fAddress;
property nationality:String read fNationality write fNationality;
property mobilePhone:String read fMobilePhone write fMobilePhone;
property generalPhone:String read fGeneralPhone write fGeneralPhone;
property officePhone:String read fOfficePhone write fOfficePhone;
property homePhone:String read fHomePhone write fHomePhone;
property email:String read fEmail write fEmail;
property qqNumber:String read fQQNumber write fQQNumber;
property category:TEmployeeCategory read fCategory write fCategory;
property post:TEmployeePost read fPost write fPost;
property bankName:String read fBankName write fBankName;
property bankAccount:String read fBankAccount write fBankAccount;
property isDeleted:Boolean read fDeleted write fDeleted;
property memo:String read fMemo write fMemo;
end;
TRoute = class(TSQLRecord)
private
fOperatorName: string;
fOperatorDate: TDateTime;
fTripNumber: string; //班次
fLine: string; //旅游线路
fDepartureDate: TDateTime; //发车日期、时间
fGuide: string; //导游
fNote: string; //备注
published
property operatorName: string read fOperatorName write fOperatorName;
property operatorDate: TDateTime read fOperatorDate write fOperatorDate;
property tripNumber: string read fTripNumber write fTripNumber;
property line: string read fLine write fLine;
property departureDate: TDateTime read fDepartureDate write fDepartureDate;
property guide: string read fGuide write fGuide;
property note: string read fNote write fNote;
end;
TTouristPriceType = (ptAdult, ptOldPeople, ptChildren);
TTourist = class(TSQLRecord)
private
fOperatorName: string;
fOperatorDate: TDateTime;
fRoute: TRoute;
fName: string; //游客姓名
fIdCard: string; //游客身份证
fMobilePhone: string; //游客手机
fGeneralPhone: string; //游客常用电话
fSeat: Integer; //座号
fPrice: Integer; //价格
fPriceType: TTouristPriceType; //票价类型,成人/老人/儿童
fSalesman: string; //推销员
fIsFromAdvertising: Boolean; //是否来自于广告
fIsFromSales: Boolean; //是否来自于营销
fIsFromHotline: Boolean; //是否来自于热线咨询
fIsFromWeb: Boolean; //是否来自于互联网
fIsFromMobileApp: Boolean; //是否来自于手机App
fIsFromWeiXin: Boolean; //是否来自于微信
fNote: string; //备注
published
property operatorName: string read fOperatorName write fOperatorName;
property operatorDate: TDateTime read fOperatorDate write fOperatorDate;
property route: TRoute read fRoute write fRoute;
property name: string read fName write fName;
property idCard: string read fIdCard write fIdCard;
property mobilePhone: string read fMobilePhone write fMobilePhone;
property generalPhone: string read fGeneralPhone write fGeneralPhone;
property seat: Integer read fSeat write fSeat;
property price: Integer read fPrice write fPrice;
property priceType: TTouristPriceType read fPriceType write fPriceType;
property salesman: string read fSalesman write fSalesman;
property isFromAdvertising: Boolean read fIsFromAdvertising write fIsFromAdvertising;
property isFromSales: Boolean read fIsFromSales write fIsFromSales;
property isFromHotline: Boolean read fISFromHotline write fIsFromHotline;
property isFromWeb: Boolean read fIsFromWeb write fIsFromWeb;
property isFromMobileApp: Boolean read fIsFromMobileApp write fIsFromMobileApp;
property isFromWeiXin: Boolean read fIsFromWeiXin write fIsFromWeiXin;
property note: string read fNote write fNote;
end;
TSurvey = class(TSQLRecord)
private
fOperatorName: string;
fOperatorDate: TDateTime;
fRoute: TRoute; //调查的旅游线路
fTourist: TTourist; //接受调查的相关旅客
fSatisfaction: Integer; //满意度
fOpinion: string; //旅客意见
fTreatment: string; //处理办法
fResults: string; //处理结果
fNote: string; //备注
published
property operatorName: string read fOperatorName write fOperatorName;
property operatorDate: TDateTime read fOperatorDate write fOperatorDate;
property route: TRoute read fRoute write fRoute;
property tourist: TTourist read fTourist write fTourist;
property satisfaction: Integer read fSatisfaction write fSatisfaction;
property opinion: string read fOpinion write fOpinion;
property treatment: string read fTreatment write fTreatment;
property results: string read fResults write fResults;
property note: string read fNote write fNote;
end;
const
RESTRestRootName = 'Tour'; //Automobile Passenger Transportation Rest
OrganizationServiceUri = 'organization';
NationalityServiceUri = 'nationality';
EmployeeCategoryServiceUri = 'employeeCategory';
EmployeePostServiceUri = 'employeePost';
EmployeeServiceUri = 'employee';
RouteServiceUri = 'royte';
TouristServiceUri = 'tourist';
SurveyServiceUri = 'survey';
function CreateRestServers(Conn: TODBCConnectionProperties):TRestServers;
implementation
function CreateRestServers(Conn: TODBCConnectionProperties):TRestServers;
var
organizationModel : TSQLModel;
organizationRest : TSQLRestServerDB;
nationalityModel : TSQLModel;
nationalityRest : TSQLRestServerDB;
empCategoryModel : TSQLModel;
empCategoryRest : TSQLRestServerDB;
empPostModel : TSQLModel;
empPostRest : TSQLRestServerDB;
employeeModel : TSQLModel;
employeeRest : TSQLRestServerDB;
routeModel : TSQLModel;
routeRest : TSQLRestServerDB;
touristModel : TSQLModel;
touristRest : TSQLRestServerDB;
surveyModel: TSQLModel;
surveyRest: TSQLRestServerDB;
begin
organizationModel := TSQLModel.Create([TOrganization], OrganizationServiceUri);
VirtualTableExternalMap(organizationModel, TOrganization, Conn, 'sys_organization')
.MapField('name','name')
.MapField('typ','type')
.MapField('parent', 'parent_id')
.MapField('parentIds','parent_ids')
.MapField('weight', 'weight')
.MapField('isEnabled', 'enabled')
.MapField('memo', 'memo');
organizationRest := TSQLRestServerDB.Create(organizationModel, ':memory:', False); // authentication=false
organizationRest.CreateMissingTables;
nationalityModel := TSQLModel.Create([TNationality], NationalityServiceUri);
VirtualTableExternalRegister(nationalityModel, TNationality, Conn, 'hr_nationality');
nationalityRest := TSQLRestServerDB.Create(nationalityModel, ':memory:', False);
nationalityRest.CreateMissingTables;
empCategoryModel := TSQLModel.Create([TEmployeeCategory], EmployeeCategoryServiceUri);
VirtualTableExternalMap(empCategoryModel, TEmployeeCategory, Conn, 'hr_category');
empCategoryRest := TSQLRestServerDB.Create(empCategoryModel, ':memory:', False);
empCategoryRest.CreateMissingTables;
empPostModel := TSQLModel.Create([TEmployeePost], EmployeePostServiceUri);
VirtualTableExternalMap(empPostModel, TEmployeePost, Conn, 'hr_post');
empPostRest := TSQLRestServerDB.Create(empPostModel, ':memory:', False);
empPostRest.CreateMissingTables;
employeeModel := TSQLModel.Create([TEmployee], EmployeeServiceUri);
VirtualTableExternalMap(employeeModel,TEmployee,Conn,'hr_employee')
.MapField('name','name')
.MapField('code','code')
.MapField('organization','organization_id')
.MapField('idcard', 'id_card')
.MapField('gender', 'gender')
.MapField('birthday', 'birthday')
.MapField('address','address')
.MapField('nationality','nationality')
.MapField('mobilePhone','mobile_phone')
.MapField('generalPhone','general_phone')
.MapField('officePhone', 'office_phone')
.MapField('homePhone', 'home_phone')
.MapField('email','email')
.MapField('qqNumber','qq_number')
.MapField('category','category_id')
.MapField('post','post_id')
.MapField('bankName','bank_name')
.MapField('bankAccount','bank_account')
.MapField('isDeleted','deleted')
.MapField('memo','memo');
employeeRest := TSQLRestServerDB.Create(employeeModel, ':memory:', False);
employeeRest.CreateMissingTables;
routeModel := TSQLModel.Create([TRoute], RouteServiceUri);
VirtualTableExternalMap(routeModel,TRoute,Conn,'tour_route')
.MapField('operatorName', 'op_name')
.MapField('operatorDate', 'op_date')
.MapField('tripNumber', 'trip_number')
.MapField('line', 'line')
.MapField('departureDate', 'departure_date')
.MapField('guide', 'guide')
.MapField('note', 'note');
routeRest := TSQLRestServerDB.Create(routeModel, ':memory:', False);
routeRest.CreateMissingTables;
touristModel := TSQLModel.Create([TTourist], TouristServiceUri);
VirtualTableExternalMap(touristModel,TTourist,Conn,'tour_tourist')
.MapField('operatorName', 'op_name')
.MapField('operatorDate', 'op_date')
.MapField('route', 'route_id')
.MapField('name', 'name')
.MapField('idcard', 'idcard')
.MapField('mobilePhone', 'mobile_phone')
.MapField('generalPhone', 'general_phone')
.MapField('seat', 'seat')
.MapField('price', 'price')
.MapField('priceType', 'price_type')
.MapField('salesman', 'salesman')
.MapField('isFromAdvertising', 'is_from_advertising')
.MapField('isFromSales', 'is_from_sales')
.MapField('isFromHotline', 'is_from_hotline')
.MapField('isFromWeb', 'is_from_web')
.MapField('isFromMobileApp', 'is_from_mobile_app')
.MapField('isFromWeiXin', 'is_from_weixin')
.MapField('note', 'note');
touristRest := TSQLRestServerDB.Create(touristModel, ':memory:', False);
touristRest.CreateMissingTables;
surveyModel := TSQLModel.Create([TSurvey], SurveyServiceUri);
VirtualTableExternalMap(surveyModel,TSurvey,Conn,'tour_survey')
.MapField('operatorName', 'op_name')
.MapField('operatorDate', 'op_date')
.MapField('route', 'route_id')
.MapField('tourist', 'tourist_id')
.MapField('satisfaction', 'satisfaction')
.MapField('opinion', 'opinion')
.MapField('treatment', 'treatment')
.MapField('results', 'results')
.MapField('note', 'note');
surveyRest := TSQLRestServerDB.Create(surveyModel, ':memory:', False);
surveyRest.CreateMissingTables;
SetLength(result, 8);
Result[0] := organizationRest;
Result[1] := nationalityRest;
Result[2] := empCategoryRest;
Result[3] := empPostRest;
Result[4] := employeeRest;
Result[5] := routeRest;
Result[6] := touristRest;
Result[7] := surveyRest;
end;
end.
procedure TMainForm.actStartExecute(Sender: TObject);
var
connectionString: String;
portString: String;
rests :TRestServers;
begin
connectionString := Format('Driver=%s;Database=%s;Server=%s;Port=%d;UID=%s;Pwd=%s', [ODBCDriver,fDatabase,fServer,fPort,fUsername,fPassword]);
fConn := TODBCConnectionProperties.Create('',connectionString, '', '');
rests := CreateRestServers(fConn);
fHttpServer := TSQLHttpServer.Create(fListenPort, rests, '+', useHttpApiRegisteringURI);
fHttpServer.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
end;
I find out TSQLRestClientDB has TransactionBegin, this means transaction call on client side, this is why server side not support concurrent writing. I think that client can use sql direct through server to operating database is not a good idea.
If REST client calls sql or something like using transaction, it would be wrong as you point: (for server side) the incoming REST requests may come in diverse threads. As far as I know , if transaction always in REST server not client, per-thread transaction is practicable, whenever client call function on server, must be completed by one time. REST Server function is atomic. So, it disallows using sql on client, client only calls functions on server, server does sql operation in transaction. every client call leads to server's per-thread do a transaction operation.
When my program obey this policy, can I set the mORMot concurrent writing?
I read the document, In 8.3.7, it said:By default, all ORM read operations will be run in concurrent mode, and all ORM write operations will be executed in blocking mode. This is expected to be both safe and fast, with our internal SQLite3 engine, or most of the external databases.
... To avoid such problems, you can force all ORM write operations to be executed in a dedicated thread, i.e. by setting amMainThread (which is not very
opportune on a server without UI), or even better via amBackgroundThread or a amBackgroundORMSharedThread
Does it mean must use dedicated thread for writing? I don't like this policy, it seems like mysql SERIALIZABLE transaction isolation levels, and can make writing bottleneck, while mysql or mssql support concurrent writing.
mORMot has connection pool, per-thread in connection pool has it own transaction, why threads can not read/write concurrently ? the ZeroC ICE can do like these.
Pages: 1