mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
First implementation for foDoNotInsert and foDoNotUpdate
This commit is contained in:
parent
09ecb5f5a1
commit
ab92225d12
@ -207,7 +207,6 @@ var
|
|||||||
lModuleName: string;
|
lModuleName: string;
|
||||||
lPath: string;
|
lPath: string;
|
||||||
lFormat: string;
|
lFormat: string;
|
||||||
lNow: TDateTime;
|
|
||||||
begin
|
begin
|
||||||
{$IF Defined(Android)}
|
{$IF Defined(Android)}
|
||||||
lModuleName := TAndroidHelper.ApplicationTitle.Replace(' ', '_', [rfReplaceAll]);
|
lModuleName := TAndroidHelper.ApplicationTitle.Replace(' ', '_', [rfReplaceAll]);
|
||||||
@ -221,7 +220,6 @@ begin
|
|||||||
lFormat := fLogFileNameFormat;
|
lFormat := fLogFileNameFormat;
|
||||||
|
|
||||||
lPath := fLogsFolder;
|
lPath := fLogsFolder;
|
||||||
lNow := Now();
|
|
||||||
lFormat := lFormat
|
lFormat := lFormat
|
||||||
.Replace('{module}', lModuleName, [rfReplaceAll])
|
.Replace('{module}', lModuleName, [rfReplaceAll])
|
||||||
.Replace('{number}', aFileNumber.ToString.PadLeft(2,'0') , [rfReplaceAll])
|
.Replace('{number}', aFileNumber.ToString.PadLeft(2,'0') , [rfReplaceAll])
|
||||||
|
@ -231,6 +231,32 @@ type
|
|||||||
property City: string read fCity write fCity;
|
property City: string read fCity write fCity;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
[MVCNameCase(ncLowerCase)]
|
||||||
|
[MVCTable('customers')]
|
||||||
|
TCustomerWithOptions = class(TCustomEntity)
|
||||||
|
private
|
||||||
|
{$IFNDEF USE_SEQUENCES}
|
||||||
|
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
|
||||||
|
{$ELSE}
|
||||||
|
[MVCTableField('id', [foPrimaryKey, foAutoGenerated],
|
||||||
|
'SEQ_CUSTOMERS_ID' { required for interbase } )]
|
||||||
|
{$ENDIF}
|
||||||
|
fID: Integer;
|
||||||
|
[MVCTableField('code', [foDoNotInsert, foDoNotUpdate])]
|
||||||
|
fCode: NullableString;
|
||||||
|
[MVCTableField('description', [foDoNotInsert])]
|
||||||
|
fCompanyName: string;
|
||||||
|
[MVCTableField('city', [foDoNotUpdate])]
|
||||||
|
fCity: string;
|
||||||
|
public
|
||||||
|
property ID: Integer read fID write fID;
|
||||||
|
property Code: NullableString read fCode write fCode;
|
||||||
|
property CompanyName: string read fCompanyName write fCompanyName;
|
||||||
|
property City: string read fCity write fCity;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
[MVCNameCase(ncLowerCase)]
|
[MVCNameCase(ncLowerCase)]
|
||||||
[MVCTable('order_details')]
|
[MVCTable('order_details')]
|
||||||
TOrderDetail = class(TCustomEntity)
|
TOrderDetail = class(TCustomEntity)
|
||||||
|
@ -2,7 +2,7 @@ object MainForm: TMainForm
|
|||||||
Left = 0
|
Left = 0
|
||||||
Top = 0
|
Top = 0
|
||||||
Caption = 'TMVCActiveRecord - ShowCase'
|
Caption = 'TMVCActiveRecord - ShowCase'
|
||||||
ClientHeight = 626
|
ClientHeight = 660
|
||||||
ClientWidth = 1094
|
ClientWidth = 1094
|
||||||
Color = clBtnFace
|
Color = clBtnFace
|
||||||
Font.Charset = DEFAULT_CHARSET
|
Font.Charset = DEFAULT_CHARSET
|
||||||
@ -14,7 +14,7 @@ object MainForm: TMainForm
|
|||||||
OnShow = FormShow
|
OnShow = FormShow
|
||||||
DesignSize = (
|
DesignSize = (
|
||||||
1094
|
1094
|
||||||
626)
|
660)
|
||||||
TextHeight = 13
|
TextHeight = 13
|
||||||
object btnCRUD: TButton
|
object btnCRUD: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
@ -27,7 +27,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnSelect: TButton
|
object btnSelect: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 242
|
Top = 283
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 33
|
Height = 33
|
||||||
Caption = 'Queries'
|
Caption = 'Queries'
|
||||||
@ -38,7 +38,7 @@ object MainForm: TMainForm
|
|||||||
Left = 280
|
Left = 280
|
||||||
Top = 8
|
Top = 8
|
||||||
Width = 806
|
Width = 806
|
||||||
Height = 610
|
Height = 644
|
||||||
Anchors = [akLeft, akTop, akRight, akBottom]
|
Anchors = [akLeft, akTop, akRight, akBottom]
|
||||||
Ctl3D = True
|
Ctl3D = True
|
||||||
DoubleBuffered = True
|
DoubleBuffered = True
|
||||||
@ -55,10 +55,11 @@ object MainForm: TMainForm
|
|||||||
TabOrder = 2
|
TabOrder = 2
|
||||||
WantReturns = False
|
WantReturns = False
|
||||||
WordWrap = False
|
WordWrap = False
|
||||||
|
ExplicitHeight = 610
|
||||||
end
|
end
|
||||||
object btnRelations: TButton
|
object btnRelations: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 281
|
Top = 322
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 35
|
Height = 35
|
||||||
Caption = 'Relations'
|
Caption = 'Relations'
|
||||||
@ -67,7 +68,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnInheritance: TButton
|
object btnInheritance: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 322
|
Top = 363
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'Inheritance'
|
Caption = 'Inheritance'
|
||||||
@ -76,7 +77,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnValidation: TButton
|
object btnValidation: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 362
|
Top = 403
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'Validation'
|
Caption = 'Validation'
|
||||||
@ -94,7 +95,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnRQL: TButton
|
object btnRQL: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 402
|
Top = 443
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'RQL Query'
|
Caption = 'RQL Query'
|
||||||
@ -240,7 +241,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnReadOnly: TButton
|
object btnReadOnly: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 442
|
Top = 483
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'Read/Only Entities'
|
Caption = 'Read/Only Entities'
|
||||||
@ -249,7 +250,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnSpeed: TButton
|
object btnSpeed: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 482
|
Top = 523
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'Metadata Speed Test'
|
Caption = 'Metadata Speed Test'
|
||||||
@ -285,7 +286,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnIntegersAsBool: TButton
|
object btnIntegersAsBool: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 522
|
Top = 563
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'Integers As Booleans'
|
Caption = 'Integers As Booleans'
|
||||||
@ -294,7 +295,7 @@ object MainForm: TMainForm
|
|||||||
end
|
end
|
||||||
object btnObjectVersion: TButton
|
object btnObjectVersion: TButton
|
||||||
Left = 8
|
Left = 8
|
||||||
Top = 562
|
Top = 603
|
||||||
Width = 121
|
Width = 121
|
||||||
Height = 34
|
Height = 34
|
||||||
Caption = 'Object Version'
|
Caption = 'Object Version'
|
||||||
@ -310,6 +311,15 @@ object MainForm: TMainForm
|
|||||||
TabOrder = 30
|
TabOrder = 30
|
||||||
OnClick = btnCustomTableClick
|
OnClick = btnCustomTableClick
|
||||||
end
|
end
|
||||||
|
object btnCRUDWithOptions: TButton
|
||||||
|
Left = 8
|
||||||
|
Top = 242
|
||||||
|
Width = 121
|
||||||
|
Height = 33
|
||||||
|
Caption = 'CRUD With Fields Opts'
|
||||||
|
TabOrder = 31
|
||||||
|
OnClick = btnCRUDWithOptionsClick
|
||||||
|
end
|
||||||
object FDConnection1: TFDConnection
|
object FDConnection1: TFDConnection
|
||||||
Left = 312
|
Left = 312
|
||||||
Top = 40
|
Top = 40
|
||||||
|
@ -63,6 +63,7 @@ type
|
|||||||
btnIntegersAsBool: TButton;
|
btnIntegersAsBool: TButton;
|
||||||
btnObjectVersion: TButton;
|
btnObjectVersion: TButton;
|
||||||
btnCustomTable: TButton;
|
btnCustomTable: TButton;
|
||||||
|
btnCRUDWithOptions: TButton;
|
||||||
procedure btnCRUDClick(Sender: TObject);
|
procedure btnCRUDClick(Sender: TObject);
|
||||||
procedure btnInheritanceClick(Sender: TObject);
|
procedure btnInheritanceClick(Sender: TObject);
|
||||||
procedure btnMultiThreadingClick(Sender: TObject);
|
procedure btnMultiThreadingClick(Sender: TObject);
|
||||||
@ -96,6 +97,7 @@ type
|
|||||||
procedure btnIntegersAsBoolClick(Sender: TObject);
|
procedure btnIntegersAsBoolClick(Sender: TObject);
|
||||||
procedure btnObjectVersionClick(Sender: TObject);
|
procedure btnObjectVersionClick(Sender: TObject);
|
||||||
procedure btnCustomTableClick(Sender: TObject);
|
procedure btnCustomTableClick(Sender: TObject);
|
||||||
|
procedure btnCRUDWithOptionsClick(Sender: TObject);
|
||||||
private
|
private
|
||||||
procedure Log(const Value: string);
|
procedure Log(const Value: string);
|
||||||
procedure LoadCustomers(const HowManyCustomers: Integer = 50);
|
procedure LoadCustomers(const HowManyCustomers: Integer = 50);
|
||||||
@ -412,6 +414,78 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.btnCRUDWithOptionsClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
lCustomer: TCustomerWithOptions;
|
||||||
|
lID: Integer;
|
||||||
|
begin
|
||||||
|
Log('** CRUD test with fields options');
|
||||||
|
lCustomer := TCustomerWithOptions.Create;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
'Code' will not be persisted on table because defined as 'foReadOnly'
|
||||||
|
}
|
||||||
|
lCustomer.Code := '1234'; // "Code" will be skipped in insert and in update as well
|
||||||
|
lCustomer.CompanyName := 'Google Inc.'; // "CompanyName" will be skipped in insert
|
||||||
|
lCustomer.City := 'Montain View, CA'; // "City" will be skipped in update
|
||||||
|
lCustomer.Insert;
|
||||||
|
lID := lCustomer.ID;
|
||||||
|
Log('Just inserted Customer ' + lID.ToString + ' with fields options');
|
||||||
|
finally
|
||||||
|
lCustomer.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//let's check that code is empty
|
||||||
|
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithOptions>(lID);
|
||||||
|
try
|
||||||
|
Assert(lCustomer.Code.IsNull); // it's null
|
||||||
|
Assert(lCustomer.CompanyName.IsEmpty); //empty string
|
||||||
|
Assert(lCustomer.City = 'Montain View, CA'); //inserted
|
||||||
|
|
||||||
|
lCustomer.Code := '1234'; // "Code" will be skipped in insert and in update as well
|
||||||
|
lCustomer.CompanyName := 'Google Inc.'; // "CompanyName" will be saved
|
||||||
|
lCustomer.City := 'Via Roma 10, ITALY'; // "City" will be skipped in update
|
||||||
|
lCustomer.Update;
|
||||||
|
finally
|
||||||
|
lCustomer.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//let's check
|
||||||
|
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithOptions>(lID);
|
||||||
|
try
|
||||||
|
Assert(lCustomer.Code.IsNull); // it's null
|
||||||
|
Assert(lCustomer.CompanyName = 'Google Inc.'); //correctly updated
|
||||||
|
Assert(lCustomer.City = 'Montain View, CA'); // not updated, mantains old value
|
||||||
|
finally
|
||||||
|
lCustomer.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
//if underlying field is not null, it is loaded as usual
|
||||||
|
TMVCActiveRecord.CurrentConnection.ExecSQL('update customers set code = ''XYZ'' where id = ?', [lID]);
|
||||||
|
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithReadOnlyFields>(lID);
|
||||||
|
try
|
||||||
|
Assert('XYZ' = lCustomer.Code);
|
||||||
|
lCustomer.CompanyName := lCustomer.CompanyName + ' changed!';
|
||||||
|
lCustomer.Code := 'this code will not be saved';
|
||||||
|
lCustomer.Update; //do not save field "code"
|
||||||
|
Log('Just updated Customer ' + lID.ToString);
|
||||||
|
finally
|
||||||
|
lCustomer.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//but being foReadOnly is not updated
|
||||||
|
lCustomer := TMVCActiveRecord.GetByPK<TCustomerWithReadOnlyFields>(lID);
|
||||||
|
try
|
||||||
|
Assert('XYZ' = lCustomer.Code);
|
||||||
|
lCustomer.Delete;
|
||||||
|
Log('Just deleted Customer ' + lID.ToString + ' with a R/O field');
|
||||||
|
finally
|
||||||
|
lCustomer.Free;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainForm.btnCRUDWithStringPKsClick(Sender: TObject);
|
procedure TMainForm.btnCRUDWithStringPKsClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
lCustomer: TCustomerWithCode;
|
lCustomer: TCustomerWithCode;
|
||||||
|
@ -66,9 +66,11 @@ type
|
|||||||
TMVCActiveRecord = class;
|
TMVCActiveRecord = class;
|
||||||
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 }
|
foAutoGenerated, { not written, read - similar to readonly }
|
||||||
foReadOnly, { not written, read }
|
foReadOnly, { not written, read - like foDoNotInsert+foDoNotUpdate }
|
||||||
foWriteOnly, { written, not read }
|
foWriteOnly, { written, not read }
|
||||||
foVersion {used for versioning, only one field with foVersion is allowed in class}
|
foVersion, {used for versioning, only one field with foVersion is allowed in class}
|
||||||
|
foDoNotInsert, { this field is not included in SQL INSERT commands }
|
||||||
|
foDoNotUpdate { this field is not included in SQL UPDATE commands }
|
||||||
);
|
);
|
||||||
TMVCActiveRecordFieldOptions = set of TMVCActiveRecordFieldOption;
|
TMVCActiveRecordFieldOptions = set of TMVCActiveRecordFieldOption;
|
||||||
TMVCEntityAction = (eaCreate, eaRetrieve, eaUpdate, eaDelete);
|
TMVCEntityAction = (eaCreate, eaRetrieve, eaUpdate, eaDelete);
|
||||||
@ -104,7 +106,7 @@ type
|
|||||||
FieldName: string;
|
FieldName: string;
|
||||||
FieldOptions: TMVCActiveRecordFieldOptions;
|
FieldOptions: TMVCActiveRecordFieldOptions;
|
||||||
DataTypeName: string;
|
DataTypeName: string;
|
||||||
Writeable, Readable, IsVersion: Boolean;
|
Writeable, Readable, Insertable, Updatable, IsVersion: Boolean;
|
||||||
procedure EndUpdates;
|
procedure EndUpdates;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -3899,7 +3901,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
Result := Result + GetFieldNameForSQL(lPair.Value.FieldName) + ' = ' +
|
Result := Result + GetFieldNameForSQL(lPair.Value.FieldName) + ' = ' +
|
||||||
GetParamNameForSQL(lPair.Value.FieldName) + ' + 1,';
|
GetParamNameForSQL(lPair.Value.FieldName) + ' + 1,';
|
||||||
end else if lPair.Value.Writeable then
|
end else if lPair.Value.Updatable then
|
||||||
begin
|
begin
|
||||||
Result := Result + GetFieldNameForSQL(lPair.Value.FieldName) + ' = :' +
|
Result := Result + GetFieldNameForSQL(lPair.Value.FieldName) + ' = :' +
|
||||||
GetParamNameForSQL(lPair.Value.FieldName) + ',';
|
GetParamNameForSQL(lPair.Value.FieldName) + ',';
|
||||||
@ -4236,13 +4238,27 @@ begin
|
|||||||
begin
|
begin
|
||||||
Writeable := false;
|
Writeable := false;
|
||||||
Readable := false;
|
Readable := false;
|
||||||
|
Insertable := False;
|
||||||
|
Updatable := False;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
Writeable := ((FieldOptions * [foReadOnly, foAutoGenerated]) = []);
|
Writeable := ((FieldOptions * [foReadOnly, foAutoGenerated]) = []);
|
||||||
Readable := (FieldOptions * [foWriteOnly]) = [];
|
Readable := not (foWriteOnly in FieldOptions);
|
||||||
|
Insertable := not (foDoNotInsert in FieldOptions);
|
||||||
|
Updatable := not (foDoNotUpdate in FieldOptions);
|
||||||
end;
|
end;
|
||||||
IsVersion := foVersion in FieldOptions;
|
IsVersion := foVersion in FieldOptions;
|
||||||
|
|
||||||
|
// field options consistency check
|
||||||
|
// if Writeable and (not Updatable) then
|
||||||
|
// begin
|
||||||
|
// raise EMVCActiveRecord.CreateFmt('Field "%s" cannot be Writeable but not Updateable', [FieldName]);
|
||||||
|
// end;
|
||||||
|
// if (not Writeable) and (Readable) and (Updatable or Insertable) then
|
||||||
|
// begin
|
||||||
|
// raise EMVCActiveRecord.CreateFmt('Field "%s" cannot be ReadOnly but (Updateable or Insertable)', [FieldName]);
|
||||||
|
// end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TMVCUnitOfWork<T> }
|
{ TMVCUnitOfWork<T> }
|
||||||
|
@ -85,7 +85,7 @@ begin
|
|||||||
|
|
||||||
for lKeyValue in TableMap.fMap do
|
for lKeyValue in TableMap.fMap do
|
||||||
begin
|
begin
|
||||||
if lKeyValue.Value.Writeable then
|
if lKeyValue.Value.Insertable then
|
||||||
begin
|
begin
|
||||||
lSB.Append(GetFieldNameForSQL(lKeyValue.Value.FieldName) + ',');
|
lSB.Append(GetFieldNameForSQL(lKeyValue.Value.FieldName) + ',');
|
||||||
end;
|
end;
|
||||||
@ -109,7 +109,7 @@ begin
|
|||||||
if lKeyValue.Value.IsVersion then
|
if lKeyValue.Value.IsVersion then
|
||||||
begin
|
begin
|
||||||
lSB.Append(OBJECT_VERSION_STARTING_VALUE + ',');
|
lSB.Append(OBJECT_VERSION_STARTING_VALUE + ',');
|
||||||
end else if lKeyValue.Value.Writeable then
|
end else if lKeyValue.Value.Insertable then
|
||||||
begin
|
begin
|
||||||
lSB.Append(':' + GetParamNameForSQL(lKeyValue.Value.FieldName) + ',');
|
lSB.Append(':' + GetParamNameForSQL(lKeyValue.Value.FieldName) + ',');
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user