mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Added dynamic properties accessors to TMVCActiveRecord descendants.
This commit is contained in:
parent
2049095872
commit
a258bae533
45
README.md
45
README.md
@ -392,9 +392,9 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma
|
||||
- Fixed! [issue388](https://github.com/danieleteti/delphimvcframework/issues/388)
|
||||
- Fixed! Has been patched a serious security bug affecting deployment configurations which uses internal WebServer to serve static files (do not affect all Apache, IIS or proxied deployments). Thanks to **Stephan Munz** to have discovered it. *Update to dmvcframework-3.2-RC5+ is required for all such kind of deployments.*
|
||||
|
||||
## Changes in upcoming version (3.2.1-carbon)
|
||||
## 3.2.1-carbon ("repo" version currently in beta)
|
||||
|
||||
### Bug Fixes and Improvements
|
||||
### Improvements and Bug Fixes
|
||||
|
||||
- [docExpansion parameter for Swagger](https://github.com/danieleteti/delphimvcframework/issues/408)
|
||||
|
||||
@ -415,6 +415,8 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma
|
||||
|
||||
- New React demo (Thanks to [Angelo Sobreira da Silva](https://github.com/angelosobreira))
|
||||
|
||||
- Serialization support for `TList<Integer>`, `TList<String>`, `TList<Boolean>` and for all `TList<T>` of simple types.
|
||||
|
||||
- Added `foReadOnly` and `foWriteOnly` as field options in `MVCTableField` attribute (used by `TMVCActiveRecord`). Currently available field options are:
|
||||
|
||||
- *foPrimaryKey* { it's the primary key of the mapped table }
|
||||
@ -505,6 +507,45 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma
|
||||
|
||||
- Added property `Context.HostingFrameworkType`. This property is of type `TMVCHostingFrameworkType` and can assume one of the following values: `hftIndy` (if the service is using the built-in Indy HTTP server) , `hftApache` (if the project is compiled as Apache module) or `hftISAPI` (if the project is compiled as ISAPI module).
|
||||
|
||||
- Added dynamic properties access to `TMVCActiveRecord` descendants. Indexed property `Attributes` is index using the property name and set/get a `TValue` representing the property value.
|
||||
|
||||
```delphi
|
||||
procedure TMainForm.btnAttributesClick(Sender: TObject);
|
||||
var
|
||||
lCustomer: TCustomer;
|
||||
lID: Integer;
|
||||
begin
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.Attributes['CompanyName'] := 'Google Inc.';
|
||||
lCustomer.Attributes['City'] := 'Montain View, CA';
|
||||
lCustomer.Attributes['Note'] := 'Hello there!';
|
||||
lCustomer.Attributes['Code'] := 'XX123';
|
||||
lCustomer.Attributes['Rating'] := 3;
|
||||
lCustomer.Insert;
|
||||
lID := lCustomer.ID;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID);
|
||||
try
|
||||
Assert('Google Inc.' =
|
||||
lCustomer.Attributes['CompanyName']
|
||||
.AsType<NullableString>().Value);
|
||||
Assert('Montain View, CA' =
|
||||
lCustomer.Attributes['City'].AsString);
|
||||
Assert('XX123' =
|
||||
lCustomer.Attributes['Code']
|
||||
.AsType<NullableString>().Value);
|
||||
Assert('Hello there!' =
|
||||
lCustomer.Attributes['Note'].AsString);
|
||||
lCustomer.Update;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
DelphiMVCFramework roadmap is always updated as-soon-as the features planned are implemented. Check the roadmap [here](roadmap.md).
|
||||
|
@ -57,7 +57,6 @@ object MainForm: TMainForm
|
||||
TabOrder = 2
|
||||
WantReturns = False
|
||||
WordWrap = False
|
||||
ExplicitHeight = 571
|
||||
end
|
||||
object btnRelations: TButton
|
||||
Left = 8
|
||||
@ -177,6 +176,15 @@ object MainForm: TMainForm
|
||||
TabOrder = 15
|
||||
OnClick = btnClientGeneratedPKClick
|
||||
end
|
||||
object btnAttributes: TButton
|
||||
Left = 8
|
||||
Top = 599
|
||||
Width = 121
|
||||
Height = 33
|
||||
Caption = 'Attributes'
|
||||
TabOrder = 16
|
||||
OnClick = btnAttributesClick
|
||||
end
|
||||
object FDConnection1: TFDConnection
|
||||
Left = 176
|
||||
Top = 56
|
||||
|
@ -44,6 +44,7 @@ type
|
||||
btnCountWithRQL: TButton;
|
||||
btnReadAndWriteOnly: TButton;
|
||||
btnClientGeneratedPK: TButton;
|
||||
btnAttributes: TButton;
|
||||
procedure btnCRUDClick(Sender: TObject);
|
||||
procedure btnInheritanceClick(Sender: TObject);
|
||||
procedure btnMultiThreadingClick(Sender: TObject);
|
||||
@ -62,6 +63,7 @@ type
|
||||
procedure btnCountWithRQLClick(Sender: TObject);
|
||||
procedure btnReadAndWriteOnlyClick(Sender: TObject);
|
||||
procedure btnClientGeneratedPKClick(Sender: TObject);
|
||||
procedure btnAttributesClick(Sender: TObject);
|
||||
private
|
||||
procedure Log(const Value: string);
|
||||
procedure LoadCustomers;
|
||||
@ -76,7 +78,6 @@ implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
uses
|
||||
MVCFramework.ActiveRecord,
|
||||
EntitiesU,
|
||||
@ -92,6 +93,48 @@ const
|
||||
CompanySuffix: array [0 .. 5] of string = ('Corp.', 'Inc.', 'Ltd.', 'Srl', 'SPA', 'doo');
|
||||
Stuff: array [0 .. 4] of string = ('Burger', 'GAS', 'Motors', 'House', 'Boats');
|
||||
|
||||
procedure TMainForm.btnAttributesClick(Sender: TObject);
|
||||
var
|
||||
lCustomer: TCustomer;
|
||||
lID: Integer;
|
||||
begin
|
||||
Log('** Dynamic Properties Access');
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.Attributes['CompanyName'] := 'Google Inc.';
|
||||
lCustomer.Attributes['City'] := 'Montain View, CA';
|
||||
lCustomer.Attributes['Note'] := 'Hello there!';
|
||||
lCustomer.Attributes['Code'] := 'XX123';
|
||||
lCustomer.Attributes['Rating'] := 3;
|
||||
lCustomer.Insert;
|
||||
lID := lCustomer.ID;
|
||||
Log('Just inserted Customer ' + lID.ToString);
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID);
|
||||
try
|
||||
Assert('Google Inc.' = lCustomer.Attributes['CompanyName'].AsType<NullableString>().Value);
|
||||
Assert('Montain View, CA' = lCustomer.Attributes['City'].AsString);
|
||||
Assert('XX123' = lCustomer.Attributes['Code'].AsType<NullableString>().Value);
|
||||
Assert('Hello there!' = lCustomer.Attributes['Note'].AsString);
|
||||
lCustomer.Update;
|
||||
Log('Just updated Customer ' + lID.ToString);
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.LoadByPK(lID);
|
||||
lCustomer.Code.Value := '9012';
|
||||
lCustomer.Update;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.btnClientGeneratedPKClick(Sender: TObject);
|
||||
var
|
||||
lCustomer: TCustomerPlainWithClientPK;
|
||||
@ -151,7 +194,8 @@ var
|
||||
lID: Integer;
|
||||
begin
|
||||
Log('** Simple CRUD test');
|
||||
Log('There are ' + TMVCActiveRecord.Count<TCustomer>().ToString + ' row/s for entity ' + TCustomer.ClassName);
|
||||
Log('There are ' + TMVCActiveRecord.Count<TCustomer>().ToString + ' row/s for entity ' +
|
||||
TCustomer.ClassName);
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
Log('Entity ' + TCustomer.ClassName + ' is mapped to table ' + lCustomer.TableName);
|
||||
@ -299,8 +343,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
Log('Now there are ' + TMVCActiveRecord.Count<TCustomerWithCode>().ToString + ' row/s for entity ' +
|
||||
TCustomerPlain.ClassName);
|
||||
Log('Now there are ' + TMVCActiveRecord.Count<TCustomerWithCode>().ToString + ' row/s for entity '
|
||||
+ TCustomerPlain.ClassName);
|
||||
TMVCActiveRecord.DeleteRQL(TCustomerWithCode, 'lt(code,"0090")');
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithCode>(lCode);
|
||||
@ -351,7 +395,8 @@ var
|
||||
lConnParams: string;
|
||||
begin
|
||||
Log('** Multithreading test');
|
||||
TMVCActiveRecord.DeleteRQL(TCustomer, 'in(City,["Rome","New York","London","Melbourne","Berlin"])');
|
||||
TMVCActiveRecord.DeleteRQL(TCustomer,
|
||||
'in(City,["Rome","New York","London","Melbourne","Berlin"])');
|
||||
|
||||
lConnParams := FDConnection1.Params.Text;
|
||||
lProc := procedure
|
||||
@ -372,7 +417,8 @@ begin
|
||||
try
|
||||
lCustomer.Code := Format('%5.5d', [TThread.CurrentThread.ThreadID, I]);
|
||||
lCustomer.City := Cities[Random(high(Cities) + 1)];
|
||||
lCustomer.CompanyName := Format('%s %s %s', [lCustomer.City, Stuff[Random(high(Stuff) + 1)],
|
||||
lCustomer.CompanyName :=
|
||||
Format('%s %s %s', [lCustomer.City, Stuff[Random(high(Stuff) + 1)],
|
||||
CompanySuffix[Random(high(CompanySuffix) + 1)]]);
|
||||
lCustomer.Note := lCustomer.CompanyName + ' is from ' + lCustomer.City;
|
||||
lCustomer.Insert;
|
||||
@ -385,10 +431,10 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
lTasks := [TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc),
|
||||
TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc),
|
||||
TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc),
|
||||
TTask.Run(lProc)];
|
||||
lTasks := [TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc),
|
||||
TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc),
|
||||
TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc),
|
||||
TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc), TTask.Run(lProc)];
|
||||
TTask.WaitForAll(lTasks);
|
||||
|
||||
ShowMessage('Just inserted ' + TMVCActiveRecord.Count(TCustomer,
|
||||
@ -401,7 +447,8 @@ var
|
||||
lID: Integer;
|
||||
begin
|
||||
Log('** Nullables Test');
|
||||
Log('There are ' + TMVCActiveRecord.Count<TCustomer>().ToString + ' row/s for entity ' + TCustomer.ClassName);
|
||||
Log('There are ' + TMVCActiveRecord.Count<TCustomer>().ToString + ' row/s for entity ' +
|
||||
TCustomer.ClassName);
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.CompanyName := 'Google Inc.';
|
||||
@ -541,7 +588,8 @@ begin
|
||||
lTest.Free;
|
||||
end;
|
||||
|
||||
Log('There are ' + TMVCActiveRecord.Count<TCustomer>().ToString + ' row/s for entity ' + TCustomer.ClassName);
|
||||
Log('There are ' + TMVCActiveRecord.Count<TCustomer>().ToString + ' row/s for entity ' +
|
||||
TCustomer.ClassName);
|
||||
lCustomer := TCustomer.Create;
|
||||
try
|
||||
lCustomer.CompanyName := 'Google Inc.';
|
||||
@ -709,7 +757,8 @@ begin
|
||||
try
|
||||
for lOrderRow in lOrderRows do
|
||||
begin
|
||||
Log(Format(' %-20s - %4d - %m', [lOrderRow.Description, lOrderRow.Quantity, lOrder.Total]));
|
||||
Log(Format(' %-20s - %4d - %m', [lOrderRow.Description, lOrderRow.Quantity,
|
||||
lOrder.Total]));
|
||||
end;
|
||||
Log('');
|
||||
finally
|
||||
@ -740,8 +789,8 @@ begin
|
||||
for lItem in lList do
|
||||
begin
|
||||
lCustomer := TCustomer(lItem);
|
||||
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault,
|
||||
lCustomer.City]));
|
||||
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
|
||||
end;
|
||||
finally
|
||||
lList.Free;
|
||||
@ -753,8 +802,8 @@ begin
|
||||
Log(lCustList.Count.ToString + ' record/s found');
|
||||
for lCustomer in lCustList do
|
||||
begin
|
||||
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault,
|
||||
lCustomer.City]));
|
||||
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
|
||||
end;
|
||||
finally
|
||||
lCustList.Free;
|
||||
@ -767,8 +816,8 @@ begin
|
||||
for lItem in lList do
|
||||
begin
|
||||
lCustomer := TCustomer(lItem);
|
||||
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault,
|
||||
lCustomer.City]));
|
||||
Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
|
||||
end;
|
||||
finally
|
||||
lList.Free;
|
||||
@ -787,20 +836,26 @@ begin
|
||||
// Bypassing the RQL parser you can use DBMS-specific features or just joining your tables.
|
||||
// This is just a sample, you can do the "select" also using the RQL engine
|
||||
if ActiveRecordConnectionsRegistry.GetCurrentBackend = 'firebird' then
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>('SELECT * FROM customers WHERE description CONTAINING ?',
|
||||
['google'])
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>
|
||||
('SELECT * FROM customers WHERE description CONTAINING ?', ['google'])
|
||||
else if ActiveRecordConnectionsRegistry.GetCurrentBackend = 'mysql' then
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>
|
||||
('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
else if ActiveRecordConnectionsRegistry.GetCurrentBackend = 'postgresql' then
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>('SELECT * FROM customers WHERE description ILIKE ''%google%''', [])
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>
|
||||
('SELECT * FROM customers WHERE description ILIKE ''%google%''', [])
|
||||
else if ActiveRecordConnectionsRegistry.GetCurrentBackend = 'sqlite' then
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>
|
||||
('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
else if ActiveRecordConnectionsRegistry.GetCurrentBackend = 'interbase' then
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>
|
||||
('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
else if ActiveRecordConnectionsRegistry.GetCurrentBackend = 'mssql' then
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
lCustomers := TMVCActiveRecord.Select<TCustomer>
|
||||
('SELECT * FROM customers WHERE description LIKE ''%google%''', [])
|
||||
else
|
||||
raise Exception.Create('Unsupported backend: ' + ActiveRecordConnectionsRegistry.GetCurrentBackend);
|
||||
raise Exception.Create('Unsupported backend: ' +
|
||||
ActiveRecordConnectionsRegistry.GetCurrentBackend);
|
||||
|
||||
try
|
||||
for lCustomer in lCustomers do
|
||||
@ -819,7 +874,8 @@ begin
|
||||
try
|
||||
while not lDS.Eof do
|
||||
begin
|
||||
Log(Format('%8.5s - %s', [lDS.FieldByName('code').AsString, lDS.FieldByName('description').AsString]));
|
||||
Log(Format('%8.5s - %s', [lDS.FieldByName('code').AsString, lDS.FieldByName('description')
|
||||
.AsString]));
|
||||
lDS.Next;
|
||||
end;
|
||||
finally
|
||||
@ -827,13 +883,14 @@ begin
|
||||
end;
|
||||
|
||||
lDS := TMVCActiveRecord.SelectDataSet
|
||||
('SELECT * FROM orders o join customers c on c.id = o.id_customer where o.order_date >= ?', [Date - 5000],
|
||||
[ftDate]);
|
||||
('SELECT * FROM orders o join customers c on c.id = o.id_customer where o.order_date >= ?',
|
||||
[Date - 5000], [ftDate]);
|
||||
try
|
||||
while not lDS.Eof do
|
||||
begin
|
||||
Log(Format('OrderDate: %12s - Customer: %s', [datetostr(lDS.FieldByName('order_date').AsDateTime),
|
||||
lDS.FieldByName('description').AsString]));
|
||||
Log(Format('OrderDate: %12s - Customer: %s',
|
||||
[datetostr(lDS.FieldByName('order_date').AsDateTime), lDS.FieldByName('description')
|
||||
.AsString]));
|
||||
lDS.Next;
|
||||
end;
|
||||
finally
|
||||
@ -842,13 +899,13 @@ begin
|
||||
|
||||
lDS := TMVCActiveRecord.SelectDataSet
|
||||
('SELECT * FROM orders o left join customers c on c.id = o.id_customer where o.order_date >= ? and c.id > ?',
|
||||
[Date - 5000, 1],
|
||||
[ftDate]);
|
||||
[Date - 5000, 1], [ftDate]);
|
||||
try
|
||||
while not lDS.Eof do
|
||||
begin
|
||||
Log(Format('OrderDate: %12s - Customer: %s', [datetostr(lDS.FieldByName('order_date').AsDateTime),
|
||||
lDS.FieldByName('description').AsString]));
|
||||
Log(Format('OrderDate: %12s - Customer: %s',
|
||||
[datetostr(lDS.FieldByName('order_date').AsDateTime), lDS.FieldByName('description')
|
||||
.AsString]));
|
||||
lDS.Next;
|
||||
end;
|
||||
finally
|
||||
@ -858,7 +915,8 @@ begin
|
||||
Log('** GetFirstByWhere');
|
||||
lCustomer := TMVCActiveRecord.GetFirstByWhere<TCustomer>('id > ?', [1]);
|
||||
try
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault]));
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault]));
|
||||
lID := lCustomer.ID;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
@ -866,7 +924,8 @@ begin
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetFirstByWhere<TCustomer>('id > ?', [1], [ftInteger]);
|
||||
try
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault]));
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault]));
|
||||
lID := lCustomer.ID;
|
||||
finally
|
||||
lCustomer.Free;
|
||||
@ -875,14 +934,16 @@ begin
|
||||
Log('** GetOneByWhere');
|
||||
lCustomer := TMVCActiveRecord.GetOneByWhere<TCustomer>('id = ?', [lID.Value]);
|
||||
try
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault]));
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault]));
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetOneByWhere<TCustomer>('id = ?', [lID.Value], [ftInteger]);
|
||||
try
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault, lCustomer.CompanyName.ValueOrDefault]));
|
||||
Log(Format('%8.5s - %s', [lCustomer.Code.ValueOrDefault,
|
||||
lCustomer.CompanyName.ValueOrDefault]));
|
||||
finally
|
||||
lCustomer.Free;
|
||||
end;
|
||||
@ -948,7 +1009,8 @@ begin
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithLogic>(lID);
|
||||
try
|
||||
Log(lCustomer.CompanyName + ' => IsLocatedInRome: ' + BoolToStr(lCustomer.IsLocatedInRome, True));
|
||||
Log(lCustomer.CompanyName + ' => IsLocatedInRome: ' +
|
||||
BoolToStr(lCustomer.IsLocatedInRome, True));
|
||||
lCustomer.Code := '';
|
||||
lCustomer.Update; // raise exception
|
||||
finally
|
||||
@ -991,8 +1053,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
Log('Now there are ' + TMVCActiveRecord.Count<TCustomerWithSpaces>().ToString + ' row/s for entity ' +
|
||||
TCustomerWithSpaces.ClassName);
|
||||
Log('Now there are ' + TMVCActiveRecord.Count<TCustomerWithSpaces>().ToString +
|
||||
' row/s for entity ' + TCustomerWithSpaces.ClassName);
|
||||
TMVCActiveRecord.DeleteRQL(TCustomerWithSpaces, 'lt(id,90)');
|
||||
|
||||
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithSpaces>(lID);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{F8576ED6-649F-4E28-B364-1F60687C75F2}</ProjectGuid>
|
||||
<ProjectVersion>18.8</ProjectVersion>
|
||||
<ProjectVersion>19.0</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>activerecord_showcase.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
@ -163,13 +163,13 @@
|
||||
</Excluded_Packages>
|
||||
</Delphi.Personality>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="BUILD" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>activerecord_showcase.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="BUILD" Class="ProjectOutput">
|
||||
<DeployFile LocalName="bin\activerecord_showcase.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>activerecord_showcase.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
@ -722,6 +722,16 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2x">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch768">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
@ -744,6 +754,16 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_LaunchDark2x">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1125">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
@ -843,6 +863,16 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2x">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch320">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
@ -854,6 +884,16 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch3x">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
@ -898,6 +938,26 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_LaunchDark2x">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_LaunchDark3x">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectAndroidManifest">
|
||||
<Platform Name="Android">
|
||||
<Operation>1</Operation>
|
||||
@ -945,6 +1005,16 @@
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSLaunchScreen">
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
|
||||
<Operation>64</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir>
|
||||
<Operation>64</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSResource">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
|
@ -58,8 +58,7 @@ type
|
||||
end;
|
||||
|
||||
TMVCActiveRecordClass = class of TMVCActiveRecord;
|
||||
TMVCActiveRecordFieldOption = (
|
||||
foPrimaryKey, { it's the primary key of the mapped table }
|
||||
TMVCActiveRecordFieldOption = (foPrimaryKey, { it's the primary key of the mapped table }
|
||||
foAutoGenerated, { not written, read - similar to readonly }
|
||||
foTransient, { not written, not read }
|
||||
foReadOnly, { not written, read }
|
||||
@ -157,12 +156,13 @@ type
|
||||
fEntityAllowedActions: TMVCEntityActions;
|
||||
fRQL2SQL: TRQL2SQL;
|
||||
procedure MapTValueToParam(aValue: TValue; const aParam: TFDParam);
|
||||
function MapNullableTValueToParam(aValue: TValue;
|
||||
const aParam: TFDParam): Boolean;
|
||||
function MapNullableTValueToParam(aValue: TValue; const aParam: TFDParam): Boolean;
|
||||
function GetPrimaryKeyIsAutogenerated: Boolean;
|
||||
procedure SetPrimaryKeyIsAutogenerated(const Value: Boolean);
|
||||
function GetPrimaryKeyFieldType: TFieldType;
|
||||
procedure SetTableName(const Value: string);
|
||||
function GetAttributes(const AttrName: string): TValue;
|
||||
procedure SetAttributes(const AttrName: string; const Value: TValue);
|
||||
protected
|
||||
fRTTIType: TRttiInstanceType;
|
||||
fProps: TArray<TRTTIField>;
|
||||
@ -181,14 +181,9 @@ type
|
||||
class function ExecQuery(const SQL: string; const Values: array of Variant): TDataSet; overload;
|
||||
class function ExecQuery(const SQL: string; const Values: array of Variant; const Connection: TFDConnection)
|
||||
: TDataSet; overload;
|
||||
class function ExecQuery(
|
||||
const SQL: string;
|
||||
const Values: array of Variant;
|
||||
const ValueTypes: array of TFieldType): TDataSet; overload;
|
||||
class function ExecQuery(
|
||||
const SQL: string;
|
||||
const Values: array of Variant;
|
||||
const ValueTypes: array of TFieldType;
|
||||
class function ExecQuery(const SQL: string; const Values: array of Variant; const ValueTypes: array of TFieldType)
|
||||
: TDataSet; overload;
|
||||
class function ExecQuery(const SQL: string; const Values: array of Variant; const ValueTypes: array of TFieldType;
|
||||
const Connection: TFDConnection): TDataSet; overload;
|
||||
procedure FillPrimaryKey(const SequenceName: string);
|
||||
function ExecNonQuery(const SQL: string; RefreshAutoGenerated: Boolean = false): int64; overload;
|
||||
@ -284,10 +279,13 @@ type
|
||||
function TableInfo: string;
|
||||
procedure LoadByDataset(const aDataSet: TDataSet; const aOptions: TMVCActiveRecordLoadOptions = []);
|
||||
procedure SetPK(const aValue: TValue);
|
||||
procedure SetPropertyValue(const aProp: TRttiProperty; const aValue: TValue);
|
||||
function GetPK: TValue;
|
||||
function TryGetPKValue(var Value: TValue; out IsNullableType: Boolean): Boolean;
|
||||
procedure AddChildren(const ChildObject: TObject);
|
||||
procedure RemoveChildren(const ChildObject: TObject);
|
||||
// dynamic access
|
||||
property Attributes[const AttrName: string]: TValue read GetAttributes write SetAttributes;
|
||||
[MVCDoNotSerialize]
|
||||
property TableName: string read fTableName write SetTableName;
|
||||
[MVCDoNotSerialize]
|
||||
@ -324,51 +322,34 @@ type
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function GetByPK<T: TMVCActiveRecord, constructor>(const aValue: string;
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string; const Params: array of Variant;
|
||||
const Options: TMVCActiveRecordLoadOptions = []): TObjectList<T>; overload;
|
||||
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType;
|
||||
const Options: TMVCActiveRecordLoadOptions = []): TObjectList<T>; overload;
|
||||
class function SelectOne<T: TMVCActiveRecord, constructor>(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType;
|
||||
const Options: TMVCActiveRecordLoadOptions = [];
|
||||
class function Select<T: TMVCActiveRecord, constructor>(const SQL: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = []): TObjectList<T>; overload;
|
||||
class function SelectOne<T: TMVCActiveRecord, constructor>(const SQL: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions = [];
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function SelectOne<T: TMVCActiveRecord, constructor>(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
class function SelectOne<T: TMVCActiveRecord, constructor>(const SQL: string; const Params: array of Variant;
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function SelectRQL<T: constructor, TMVCActiveRecord>(const RQL: string; const MaxRecordCount: Integer)
|
||||
: TObjectList<T>; overload;
|
||||
class function SelectOneByRQL<T: constructor, TMVCActiveRecord>(
|
||||
const RQL: string;
|
||||
class function SelectOneByRQL<T: constructor, TMVCActiveRecord>(const RQL: string;
|
||||
const RaiseExceptionIfNotFound: Boolean): T; overload;
|
||||
class function All<T: TMVCActiveRecord, constructor>: TObjectList<T>; overload;
|
||||
class function Count<T: TMVCActiveRecord>(const RQL: string = ''): int64; overload;
|
||||
class function Where<T: TMVCActiveRecord, constructor>(
|
||||
const SQLWhere: string;
|
||||
const Params: array of Variant): TObjectList<T>; overload;
|
||||
class function Where<T: TMVCActiveRecord, constructor>(
|
||||
const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
class function Where<T: TMVCActiveRecord, constructor>(const SQLWhere: string; const Params: array of Variant)
|
||||
: TObjectList<T>; overload;
|
||||
class function Where<T: TMVCActiveRecord, constructor>(const SQLWhere: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType): TObjectList<T>; overload;
|
||||
class function GetOneByWhere<T: TMVCActiveRecord, constructor>(
|
||||
const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function GetOneByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType;
|
||||
const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function GetOneByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
|
||||
const Params: array of Variant; const ParamTypes: array of TFieldType;
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function GetFirstByWhere<T: TMVCActiveRecord, constructor>(
|
||||
const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function GetFirstByWhere<T: TMVCActiveRecord, constructor>(
|
||||
const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType;
|
||||
class function GetFirstByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
|
||||
const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
class function GetFirstByWhere<T: TMVCActiveRecord, constructor>(const SQLWhere: string;
|
||||
const Params: array of Variant; const ParamTypes: array of TFieldType;
|
||||
const RaiseExceptionIfNotFound: Boolean = True): T; overload;
|
||||
end;
|
||||
|
||||
@ -448,8 +429,7 @@ type
|
||||
function GetCompiler: TRQLCompiler;
|
||||
function GetCompilerClass: TRQLCompilerClass; virtual; abstract;
|
||||
function GetMapping: TMVCFieldsMapping;
|
||||
function TableFieldsDelimited(const Map: TFieldsMap; const PKFieldName: string;
|
||||
const Delimiter: string): string;
|
||||
function TableFieldsDelimited(const Map: TFieldsMap; const PKFieldName: string; const Delimiter: string): string;
|
||||
public
|
||||
constructor Create(Mapping: TMVCFieldsMapping); virtual;
|
||||
destructor Destroy; override;
|
||||
@ -458,25 +438,21 @@ type
|
||||
function HasReturning: Boolean; virtual;
|
||||
// end-capabilities
|
||||
function CreateSQLWhereByRQL(const RQL: string; const Mapping: TMVCFieldsMapping;
|
||||
const UseArtificialLimit: Boolean = True;
|
||||
const UseFilterOnly: Boolean = false
|
||||
): string; virtual; abstract;
|
||||
function CreateSelectSQL(const TableName: string; const Map: TFieldsMap;
|
||||
const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateSelectByPKSQL(const TableName: string; const Map: TFieldsMap;
|
||||
const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string;
|
||||
virtual; abstract;
|
||||
function CreateInsertSQL(const TableName: string; const Map: TFieldsMap;
|
||||
const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateUpdateSQL(const TableName: string; const Map: TFieldsMap;
|
||||
const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateDeleteSQL(const TableName: string; const Map: TFieldsMap;
|
||||
const PKFieldName: string; const PKOptions: TMVCActiveRecordFieldOptions): string;
|
||||
virtual; abstract;
|
||||
const UseArtificialLimit: Boolean = True; const UseFilterOnly: Boolean = false): string; virtual; abstract;
|
||||
function CreateSelectSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
|
||||
const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateSelectByPKSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
|
||||
const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateInsertSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
|
||||
const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateUpdateSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
|
||||
const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateDeleteSQL(const TableName: string; const Map: TFieldsMap; const PKFieldName: string;
|
||||
const PKOptions: TMVCActiveRecordFieldOptions): string; virtual; abstract;
|
||||
function CreateDeleteAllSQL(const TableName: string): string; virtual; abstract;
|
||||
function CreateSelectCount(const TableName: string): string; virtual; abstract;
|
||||
function GetSequenceValueSQL(
|
||||
const PKFieldName: string; const SequenceName: string; const Step: Integer = 1): string; virtual;
|
||||
function GetSequenceValueSQL(const PKFieldName: string; const SequenceName: string; const Step: Integer = 1)
|
||||
: string; virtual;
|
||||
|
||||
// Overwritten by descendant if the SQL syntaxt requires more than the simple table name
|
||||
// or if the table name contains spaces.
|
||||
@ -523,6 +499,7 @@ uses
|
||||
MVCFramework.DataSet.Utils,
|
||||
MVCFramework.Logger,
|
||||
MVCFramework.Nullables,
|
||||
MVCFramework.RTTI.Utils,
|
||||
FireDAC.Stan.Option,
|
||||
Data.FmtBcd, System.Variants;
|
||||
|
||||
@ -633,8 +610,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCConnectionsRepository.AddDefaultConnection(
|
||||
const aConnection: TFDConnection; const aOwns: Boolean);
|
||||
procedure TMVCConnectionsRepository.AddDefaultConnection(const aConnection: TFDConnection; const aOwns: Boolean);
|
||||
begin
|
||||
AddConnection('default', aConnection, aOwns);
|
||||
end;
|
||||
@ -1068,8 +1044,7 @@ begin
|
||||
Result := GetScalar(lSQL, []);
|
||||
end;
|
||||
|
||||
function TMVCActiveRecord.InternalSelectRQL(const RQL: string;
|
||||
const MaxRecordCount: Integer): TMVCActiveRecordList;
|
||||
function TMVCActiveRecord.InternalSelectRQL(const RQL: string; const MaxRecordCount: Integer): TMVCActiveRecordList;
|
||||
var
|
||||
lSQL: string;
|
||||
begin
|
||||
@ -1099,6 +1074,17 @@ begin
|
||||
Result := SQLGenerator.CreateSelectSQL(fTableName, fMap, fPrimaryKeyFieldName, fPrimaryKeyOptions);
|
||||
end;
|
||||
|
||||
function TMVCActiveRecord.GetAttributes(const AttrName: string): TValue;
|
||||
var
|
||||
lProperty: TRttiProperty;
|
||||
begin
|
||||
if not TRttiUtils.ExistsProperty(Self, AttrName, lProperty) then
|
||||
begin
|
||||
raise EMVCActiveRecord.CreateFmt('Attribute [%s] not found', [AttrName]);
|
||||
end;
|
||||
Result := lProperty.GetValue(Self);
|
||||
end;
|
||||
|
||||
function TMVCActiveRecord.GetBackEnd: string;
|
||||
begin
|
||||
if fBackendDriver.IsEmpty then
|
||||
@ -1108,8 +1094,7 @@ begin
|
||||
Result := fBackendDriver;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass;
|
||||
const aValue: string;
|
||||
class function TMVCActiveRecord.GetByPK(const aClass: TMVCActiveRecordClass; const aValue: string;
|
||||
const RaiseExceptionIfNotFound: Boolean): TMVCActiveRecord;
|
||||
begin
|
||||
Result := aClass.Create;
|
||||
@ -1171,8 +1156,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.GetByPK<T>(const aValue: string;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
class function TMVCActiveRecordHelper.GetByPK<T>(const aValue: string; const RaiseExceptionIfNotFound: Boolean): T;
|
||||
var
|
||||
lActiveRecord: TMVCActiveRecord;
|
||||
begin
|
||||
@ -1192,9 +1176,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.GetFirstByWhere<T>(const SQLWhere: string;
|
||||
const Params: array of Variant; const ParamTypes: array of TFieldType;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
class function TMVCActiveRecordHelper.GetFirstByWhere<T>(const SQLWhere: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType; const RaiseExceptionIfNotFound: Boolean): T;
|
||||
var
|
||||
lList: TObjectList<T>;
|
||||
begin
|
||||
@ -1218,9 +1201,8 @@ begin
|
||||
Result := GetFirstByWhere<T>(SQLWhere, Params, [], RaiseExceptionIfNotFound);
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.GetOneByWhere<T>(const SQLWhere: string;
|
||||
const Params: array of Variant; const ParamTypes: array of TFieldType;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
class function TMVCActiveRecordHelper.GetOneByWhere<T>(const SQLWhere: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType; const RaiseExceptionIfNotFound: Boolean): T;
|
||||
begin
|
||||
Result := GetFirstByWhere<T>(SQLWhere, Params, ParamTypes, false);
|
||||
if Result = nil then
|
||||
@ -1261,9 +1243,7 @@ begin
|
||||
Result := fMapping;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.GetOneByWhere<T>(
|
||||
const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
class function TMVCActiveRecordHelper.GetOneByWhere<T>(const SQLWhere: string; const Params: array of Variant;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
begin
|
||||
Result := GetFirstByWhere<T>(SQLWhere, Params, false);
|
||||
@ -1274,9 +1254,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.SelectOneByRQL<T>(
|
||||
const RQL: string;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
class function TMVCActiveRecordHelper.SelectOneByRQL<T>(const RQL: string; const RaiseExceptionIfNotFound: Boolean): T;
|
||||
var
|
||||
lAR: TMVCActiveRecord;
|
||||
lSQL: string;
|
||||
@ -1414,15 +1392,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCActiveRecord.MapDatasetToObject(const DataSet: TDataSet;
|
||||
const Options: TMVCActiveRecordLoadOptions;
|
||||
procedure TMVCActiveRecord.MapDatasetToObject(const DataSet: TDataSet; const Options: TMVCActiveRecordLoadOptions;
|
||||
var Handled: Boolean);
|
||||
begin
|
||||
// do nothing
|
||||
end;
|
||||
|
||||
procedure TMVCActiveRecord.MapObjectToParams(const Params: TFDParams;
|
||||
var Handled: Boolean);
|
||||
procedure TMVCActiveRecord.MapObjectToParams(const Params: TFDParams; var Handled: Boolean);
|
||||
begin
|
||||
// do nothing
|
||||
end;
|
||||
@ -1704,18 +1680,15 @@ begin
|
||||
begin
|
||||
aParam.AsDate := Trunc(aValue.AsExtended);
|
||||
end
|
||||
else
|
||||
if lName = 'TDateTime' then
|
||||
else if lName = 'TDateTime' then
|
||||
begin
|
||||
aParam.AsDateTime := aValue.AsExtended;
|
||||
end
|
||||
else
|
||||
if lName = 'TTime' then
|
||||
else if lName = 'TTime' then
|
||||
begin
|
||||
aParam.AsTime := aValue.AsExtended;
|
||||
end
|
||||
else
|
||||
if lName = 'Currency' then
|
||||
else if lName = 'Currency' then
|
||||
begin
|
||||
aParam.AsCurrency := aValue.AsCurrency;
|
||||
end
|
||||
@ -2043,8 +2016,7 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecord.SelectDataSet(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
class function TMVCActiveRecord.SelectDataSet(const SQL: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType): TDataSet;
|
||||
begin
|
||||
Result := TMVCActiveRecord.ExecQuery(SQL, Params, ParamTypes);
|
||||
@ -2066,10 +2038,8 @@ begin
|
||||
Result := InternalSelectRQL(RQL, MaxRecordCount);
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.Select<T>(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType;
|
||||
const Options: TMVCActiveRecordLoadOptions): TObjectList<T>;
|
||||
class function TMVCActiveRecordHelper.Select<T>(const SQL: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions): TObjectList<T>;
|
||||
var
|
||||
lDataSet: TDataSet;
|
||||
lAR: TMVCActiveRecord;
|
||||
@ -2095,16 +2065,14 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.SelectOne<T>(const SQL: string;
|
||||
const Params: array of Variant; const RaiseExceptionIfNotFound: Boolean): T;
|
||||
class function TMVCActiveRecordHelper.SelectOne<T>(const SQL: string; const Params: array of Variant;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
begin
|
||||
Result := SelectOne<T>(SQL, Params, [], [], RaiseExceptionIfNotFound);
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.SelectOne<T>(const SQL: string;
|
||||
const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType;
|
||||
const Options: TMVCActiveRecordLoadOptions;
|
||||
class function TMVCActiveRecordHelper.SelectOne<T>(const SQL: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType; const Options: TMVCActiveRecordLoadOptions;
|
||||
const RaiseExceptionIfNotFound: Boolean): T;
|
||||
var
|
||||
lDataSet: TDataSet;
|
||||
@ -2149,8 +2117,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string;
|
||||
const Params: array of Variant;
|
||||
class function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string; const Params: array of Variant;
|
||||
const ParamTypes: array of TFieldType): TObjectList<T>;
|
||||
var
|
||||
lAR: TMVCActiveRecord;
|
||||
@ -2183,15 +2150,160 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCActiveRecord.SetAttributes(const AttrName: string; const Value: TValue);
|
||||
var
|
||||
lProperty: TRttiProperty;
|
||||
begin
|
||||
if not TRttiUtils.ExistsProperty(Self, AttrName, lProperty) then
|
||||
begin
|
||||
raise EMVCActiveRecord.CreateFmt('Attribute [%s] not found', [AttrName]);
|
||||
end;
|
||||
SetPropertyValue(lProperty, Value);
|
||||
end;
|
||||
|
||||
procedure TMVCActiveRecord.SetPropertyValue(const aProp: TRttiProperty; const aValue: TValue);
|
||||
var
|
||||
lCurrValue: TValue;
|
||||
lNullableString: NullableString;
|
||||
lNullableUInt32: NullableUInt32;
|
||||
lNullableUInt64: NullableUInt64;
|
||||
lNullableInt64: NullableInt64;
|
||||
lNullableBoolean: NullableBoolean;
|
||||
lNullableTDateTime: NullableTDateTime;
|
||||
lNullableTDate: NullableTDate;
|
||||
lNullableTTime: NullableTTime;
|
||||
begin
|
||||
if aProp.GetValue(Self).Kind = tkRecord then
|
||||
begin
|
||||
lCurrValue := aProp.GetValue(Self);
|
||||
if lCurrValue.IsType<NullableInt32> then
|
||||
begin
|
||||
if aValue.IsType<NullableInt32>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lCurrValue := TValue.From<NullableInt32>(IntToNullableInt(aValue.AsInteger));
|
||||
end
|
||||
end
|
||||
else if lCurrValue.IsType<NullableInt64> then
|
||||
begin
|
||||
if aValue.IsType<NullableInt64>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableInt64 := aValue.AsInt64;
|
||||
lCurrValue := TValue.From<NullableInt64>(lNullableInt64);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableString> then
|
||||
begin
|
||||
if aValue.IsType<NullableString>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableString := aValue.AsString;
|
||||
lCurrValue := TValue.From<NullableString>(lNullableString);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableUInt32> then
|
||||
begin
|
||||
if aValue.IsType<NullableUInt32>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableUInt32 := aValue.AsInteger;
|
||||
lCurrValue.From<NullableUInt32>(lNullableUInt32);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableUInt64> then
|
||||
begin
|
||||
if aValue.IsType<NullableUInt64>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableUInt64 := aValue.AsUInt64;
|
||||
lCurrValue.From<NullableUInt64>(lNullableUInt64);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableBoolean> then
|
||||
begin
|
||||
if aValue.IsType<NullableBoolean>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableBoolean := aValue.AsBoolean;
|
||||
lCurrValue.From<NullableBoolean>(lNullableBoolean);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableTDateTime> then
|
||||
begin
|
||||
if aValue.IsType<NullableTDateTime>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableTDateTime := TDateTime(aValue.AsExtended);
|
||||
lCurrValue.From<NullableTDateTime>(lNullableTDateTime);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableTDate> then
|
||||
begin
|
||||
if aValue.IsType<NullableTDate>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableTDate := TDate(aValue.AsExtended);
|
||||
lCurrValue.From<NullableTDate>(lNullableTDate);
|
||||
end;
|
||||
end
|
||||
else if lCurrValue.IsType<NullableTTime> then
|
||||
begin
|
||||
if aValue.IsType<NullableTTime>() then
|
||||
begin
|
||||
lCurrValue := aValue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
lNullableTTime := TTime(aValue.AsExtended);
|
||||
lCurrValue.From<NullableTTime>(lNullableTTime);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
raise EMVCActiveRecord.Create('Invalid data type for dynamic property access');
|
||||
end;
|
||||
aProp.SetValue(Self, lCurrValue);
|
||||
end
|
||||
else
|
||||
begin
|
||||
aProp.SetValue(Self, aValue)
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCActiveRecord.SetPK(const aValue: TValue);
|
||||
var
|
||||
lPKValue: TValue;
|
||||
|
||||
begin
|
||||
if fPrimaryKeyFieldName.IsEmpty then
|
||||
begin
|
||||
raise Exception.Create('No primary key defined');
|
||||
end;
|
||||
|
||||
if fPrimaryKey.GetValue(Self).Kind = tkRecord then
|
||||
begin
|
||||
lPKValue := fPrimaryKey.GetValue(Self);
|
||||
@ -2248,7 +2360,8 @@ begin
|
||||
end
|
||||
else
|
||||
begin
|
||||
raise EMVCActiveRecord.Create('Invalid type for primary key [HINT] Double check if TypeInfo(PK) is equal to TypeInfo(Value)');
|
||||
raise EMVCActiveRecord.Create
|
||||
('Invalid type for primary key [HINT] Double check if TypeInfo(PK) is equal to TypeInfo(Value)');
|
||||
end;
|
||||
fPrimaryKey.SetValue(Self, lPKValue);
|
||||
end
|
||||
@ -2407,8 +2520,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecord.All(const aClass: TMVCActiveRecordClass): TObjectList<TMVCActiveRecord>;
|
||||
class function TMVCActiveRecord.All(const aClass: TMVCActiveRecordClass): TObjectList<TMVCActiveRecord>;
|
||||
var
|
||||
lAR: TMVCActiveRecord;
|
||||
begin
|
||||
@ -2420,8 +2532,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecordHelper.All<T>: TObjectList<T>;
|
||||
class function TMVCActiveRecordHelper.All<T>: TObjectList<T>;
|
||||
var
|
||||
lAR: TMVCActiveRecord;
|
||||
begin
|
||||
@ -2433,15 +2544,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
|
||||
class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
|
||||
const Params: array of Variant): TMVCActiveRecordList;
|
||||
begin
|
||||
Result := Where(aClass, SQLWhere, Params, nil);
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
|
||||
class function TMVCActiveRecord.Where(const aClass: TMVCActiveRecordClass; const SQLWhere: string;
|
||||
const Params: array of Variant; const Connection: TFDConnection): TMVCActiveRecordList;
|
||||
var
|
||||
lAR: TMVCActiveRecord;
|
||||
@ -2454,8 +2563,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string; const Params: array of Variant): TObjectList<T>;
|
||||
class function TMVCActiveRecordHelper.Where<T>(const SQLWhere: string; const Params: array of Variant): TObjectList<T>;
|
||||
begin
|
||||
Result := Where<T>(SQLWhere, Params, []);
|
||||
end;
|
||||
@ -2567,8 +2675,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCSQLGeneratorRegistry.Instance: TMVCSQLGeneratorRegistry;
|
||||
class function TMVCSQLGeneratorRegistry.Instance: TMVCSQLGeneratorRegistry;
|
||||
begin
|
||||
if not Assigned(cInstance) then
|
||||
begin
|
||||
@ -2645,8 +2752,8 @@ begin
|
||||
Result := fRQL2SQL;
|
||||
end;
|
||||
|
||||
function TMVCSQLGenerator.GetSequenceValueSQL(
|
||||
const PKFieldName: string; const SequenceName: string; const Step: Integer = 1): string;
|
||||
function TMVCSQLGenerator.GetSequenceValueSQL(const PKFieldName: string; const SequenceName: string;
|
||||
const Step: Integer = 1): string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
@ -2724,12 +2831,8 @@ begin
|
||||
fHttpErrorCode := http_status.NotFound;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecord.ExecQuery(
|
||||
const SQL: string;
|
||||
const Values: array of Variant;
|
||||
const ValueTypes: array of TFieldType;
|
||||
const Connection: TFDConnection): TDataSet;
|
||||
class function TMVCActiveRecord.ExecQuery(const SQL: string; const Values: array of Variant;
|
||||
const ValueTypes: array of TFieldType; const Connection: TFDConnection): TDataSet;
|
||||
var
|
||||
lQry: TFDQuery;
|
||||
begin
|
||||
@ -2761,9 +2864,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class
|
||||
function TMVCActiveRecord.ExecQuery(const SQL: string;
|
||||
const Values: array of Variant;
|
||||
class function TMVCActiveRecord.ExecQuery(const SQL: string; const Values: array of Variant;
|
||||
const ValueTypes: array of TFieldType): TDataSet;
|
||||
begin
|
||||
Result := ExecQuery(SQL, Values, ValueTypes, nil);
|
||||
|
Loading…
Reference in New Issue
Block a user