2018-09-25 15:36:53 +02:00
|
|
|
unit Entities;
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
MVCFramework.Serializer.Commons,
|
|
|
|
MVCFramework.ActiveRecord,
|
2022-08-01 11:18:46 +02:00
|
|
|
MVCFramework.Nullables,
|
2018-10-23 16:18:34 +02:00
|
|
|
System.Classes,
|
2022-10-09 15:45:59 +02:00
|
|
|
System.DateUtils,
|
|
|
|
MVCFramework,
|
|
|
|
MVCFramework.Utils,
|
|
|
|
System.Generics.Collections;
|
2018-09-25 15:36:53 +02:00
|
|
|
|
|
|
|
type
|
|
|
|
|
2022-08-02 23:57:09 +02:00
|
|
|
[MVCNameCase(ncCamelCase)]
|
2019-02-21 20:17:11 +01:00
|
|
|
[MVCTable('people')]
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCEntityActions([eaCreate, eaRetrieve, eaUpdate, eaDelete])]
|
2018-09-25 15:36:53 +02:00
|
|
|
TPerson = class(TMVCActiveRecord)
|
|
|
|
private
|
2019-03-05 20:55:37 +01:00
|
|
|
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
|
2018-09-25 15:36:53 +02:00
|
|
|
fID: Int64;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('LAST_NAME')]
|
2018-09-25 15:36:53 +02:00
|
|
|
fLastName: string;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('FIRST_NAME')]
|
2018-09-25 15:36:53 +02:00
|
|
|
fFirstName: string;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('DOB')]
|
2022-08-01 11:18:46 +02:00
|
|
|
fDOB: NullableTDate;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('FULL_NAME')]
|
2018-09-25 15:36:53 +02:00
|
|
|
fFullName: string;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('IS_MALE')]
|
2022-08-01 11:18:46 +02:00
|
|
|
fIsMale: NullableBoolean;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('NOTE')]
|
2018-09-25 15:36:53 +02:00
|
|
|
fNote: string;
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCTableField('PHOTO')]
|
2018-09-25 15:36:53 +02:00
|
|
|
fPhoto: TStream;
|
|
|
|
|
|
|
|
// transient fields
|
2022-08-01 11:18:46 +02:00
|
|
|
fAge: NullableInt32;
|
2018-09-25 15:36:53 +02:00
|
|
|
|
|
|
|
procedure SetLastName(const Value: string);
|
|
|
|
procedure SetID(const Value: Int64);
|
|
|
|
procedure SetFirstName(const Value: string);
|
2022-08-01 11:18:46 +02:00
|
|
|
procedure SetDOB(const Value: NullableTDate);
|
2018-09-25 15:36:53 +02:00
|
|
|
function GetFullName: string;
|
2022-08-01 11:18:46 +02:00
|
|
|
procedure SetIsMale(const Value: NullableBoolean);
|
2018-09-25 15:36:53 +02:00
|
|
|
procedure SetNote(const Value: string);
|
|
|
|
protected
|
|
|
|
procedure OnAfterLoad; override;
|
|
|
|
procedure OnBeforeInsertOrUpdate; override;
|
2020-03-31 20:53:03 +02:00
|
|
|
procedure OnValidation(const Action: TMVCEntityAction); override;
|
2018-09-25 15:36:53 +02:00
|
|
|
procedure OnBeforeInsert; override;
|
|
|
|
public
|
|
|
|
constructor Create; override;
|
|
|
|
destructor Destroy; override;
|
2022-10-09 15:45:59 +02:00
|
|
|
function GetUniqueString: String;
|
|
|
|
procedure Assign(ActiveRecord: TMVCActiveRecord); override;
|
2018-09-25 15:36:53 +02:00
|
|
|
property ID: Int64 read fID write SetID;
|
2022-08-02 23:57:09 +02:00
|
|
|
[MVCNameAs('person_surname')]
|
2018-09-25 15:36:53 +02:00
|
|
|
property LastName: string read fLastName write SetLastName;
|
2022-08-02 23:57:09 +02:00
|
|
|
[MVCNameAs('person_name')]
|
2018-09-25 15:36:53 +02:00
|
|
|
property FirstName: string read fFirstName write SetFirstName;
|
2022-08-01 11:18:46 +02:00
|
|
|
property Age: NullableInt32 read fAge;
|
|
|
|
property DOB: NullableTDate read fDOB write SetDOB;
|
2018-09-25 15:36:53 +02:00
|
|
|
property FullName: string read GetFullName;
|
2022-08-01 11:18:46 +02:00
|
|
|
property IsMale: NullableBoolean read fIsMale write SetIsMale;
|
2018-09-25 15:36:53 +02:00
|
|
|
property Note: string read fNote write SetNote;
|
|
|
|
property Photo: TStream read fPhoto;
|
|
|
|
end;
|
|
|
|
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCNameCase(ncLowerCase)]
|
2019-02-21 20:17:11 +01:00
|
|
|
[MVCTable('phones')]
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCEntityActions([eaCreate, eaRetrieve, eaUpdate, eaDelete])]
|
|
|
|
TPhone = class(TMVCActiveRecord)
|
|
|
|
private
|
2019-03-05 20:55:37 +01:00
|
|
|
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
|
2018-10-23 16:18:34 +02:00
|
|
|
fID: Integer;
|
|
|
|
[MVCTableField('phone_number')]
|
|
|
|
fPhoneNumber: string;
|
|
|
|
[MVCTableField('number_type')]
|
|
|
|
fNumberType: string;
|
|
|
|
[MVCTableField('id_person')]
|
|
|
|
fIDPerson: Integer;
|
|
|
|
protected
|
2020-03-31 20:53:03 +02:00
|
|
|
procedure OnValidation(const Action: TMVCEntityAction); override;
|
2018-10-23 16:18:34 +02:00
|
|
|
public
|
|
|
|
property ID: Integer read fID write fID;
|
|
|
|
property IDPerson: Integer read fIDPerson write fIDPerson;
|
|
|
|
property PhoneNumber: string read fPhoneNumber write fPhoneNumber;
|
|
|
|
property NumberType: string read fNumberType write fNumberType;
|
|
|
|
end;
|
|
|
|
|
2020-10-24 14:21:02 +02:00
|
|
|
[MVCNameCase(ncLowerCase)]
|
|
|
|
[MVCTable('PEOPLE')]
|
|
|
|
[MVCEntityActions([eaCreate, eaRetrieve, eaUpdate, eaDelete])]
|
|
|
|
TContact = class(TPerson)
|
|
|
|
private
|
|
|
|
function GetPhones: TObjectList<TPhone>;
|
|
|
|
public
|
|
|
|
property Phones: TObjectList<TPhone> read GetPhones;
|
|
|
|
end;
|
|
|
|
|
2023-09-05 15:27:05 +02:00
|
|
|
[MVCNameCase(ncLowerCase)]
|
|
|
|
[MVCEntityActions([eaRetrieve])]
|
|
|
|
[MVCNamedSQLQuery('AverageSalary',
|
|
|
|
'select person_type, coalesce(avg(salary::numeric), 0) average_salary from people ' +
|
|
|
|
'group by person_type order by 1', TMVCActiveRecordBackEnd.PostgreSQL)]
|
|
|
|
TSalaryAggregate = class(TMVCActiveRecord)
|
|
|
|
private
|
|
|
|
[MVCTableField('average_salary')]
|
|
|
|
FAverageSalary: Currency;
|
|
|
|
[MVCTableField('person_type')]
|
|
|
|
FPersonType: String;
|
|
|
|
procedure SetAverageSalary(const Value: Currency);
|
|
|
|
procedure SetPersonType(const Value: String);
|
|
|
|
public
|
|
|
|
property PersonType: String read FPersonType write SetPersonType;
|
|
|
|
property AverageSalary: Currency read FAverageSalary write SetAverageSalary;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCNameCase(ncLowerCase)]
|
2019-02-21 20:17:11 +01:00
|
|
|
[MVCTable('articles')]
|
2018-10-23 16:18:34 +02:00
|
|
|
[MVCEntityActions([eaCreate, eaRetrieve, eaUpdate, eaDelete])]
|
2018-10-14 18:23:20 +02:00
|
|
|
TArticle = class(TMVCActiveRecord)
|
|
|
|
private
|
2019-03-05 20:55:37 +01:00
|
|
|
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
|
2018-10-14 18:23:20 +02:00
|
|
|
fID: Int64;
|
2019-02-21 20:17:11 +01:00
|
|
|
[MVCTableField('price')]
|
2021-04-08 00:33:27 +02:00
|
|
|
FPrice: UInt32;
|
2019-02-21 20:17:11 +01:00
|
|
|
[MVCTableField('description')]
|
2018-10-14 18:23:20 +02:00
|
|
|
FDescription: string;
|
|
|
|
procedure SetID(const Value: Int64);
|
|
|
|
procedure SetDescription(const Value: string);
|
2021-04-08 00:33:27 +02:00
|
|
|
procedure SetPrice(const Value: UInt32);
|
2018-10-14 18:23:20 +02:00
|
|
|
public
|
|
|
|
property ID: Int64 read fID write SetID;
|
|
|
|
property Description: string read FDescription write SetDescription;
|
2021-04-08 00:33:27 +02:00
|
|
|
property Price: UInt32 read FPrice write SetPrice;
|
2018-10-14 18:23:20 +02:00
|
|
|
end;
|
|
|
|
|
2023-11-27 18:11:49 +01:00
|
|
|
[MVCNameCase(ncLowerCase)]
|
|
|
|
[MVCTable('customers_with_version')]
|
|
|
|
TCustomersWithVersion = class(TMVCActiveRecord)
|
|
|
|
private
|
|
|
|
[MVCTableField('id', [foPrimaryKey, foAutoGenerated])]
|
|
|
|
fID: Int64;
|
|
|
|
[MVCTableField('code')]
|
|
|
|
fCode: NullableString;
|
|
|
|
[MVCTableField('description')]
|
|
|
|
fDescription: NullableString;
|
|
|
|
[MVCTableField('city')]
|
|
|
|
fCity: NullableString;
|
|
|
|
[MVCTableField('note')]
|
|
|
|
fNote: NullableString;
|
|
|
|
[MVCTableField('rating')]
|
|
|
|
fRating: NullableInt32;
|
|
|
|
[MVCTableField('objversion', [foVersion])]
|
|
|
|
fObjversion: Integer;
|
|
|
|
public
|
|
|
|
property ID: Int64 read fID write fID;
|
|
|
|
property Code: NullableString read fCode write fCode;
|
|
|
|
property Description: NullableString read fDescription write fDescription;
|
|
|
|
property City: NullableString read fCity write fCity;
|
|
|
|
property Note: NullableString read fNote write fNote;
|
|
|
|
property Rating: NullableInt32 read fRating write fRating;
|
|
|
|
property ObjVersion: Integer read fObjversion write fObjversion;
|
|
|
|
end;
|
|
|
|
|
2018-09-25 15:36:53 +02:00
|
|
|
implementation
|
|
|
|
|
|
|
|
uses
|
|
|
|
System.SysUtils;
|
|
|
|
|
|
|
|
{ TPersona }
|
|
|
|
|
2022-10-09 15:45:59 +02:00
|
|
|
procedure TPerson.Assign(ActiveRecord: TMVCActiveRecord);
|
|
|
|
begin
|
|
|
|
if ActiveRecord is TPerson then
|
|
|
|
begin
|
|
|
|
var lPerson := TPerson(ActiveRecord);
|
|
|
|
Self.LastName := lPerson.LastName;
|
|
|
|
Self.FirstName := lPerson.FirstName;
|
|
|
|
Self.DOB := lPerson.DOB;
|
|
|
|
Self.IsMale := lPerson.IsMale;
|
|
|
|
Self.Note := lPerson.Note;
|
|
|
|
Self.Photo.Size := 0;
|
|
|
|
Self.Photo.CopyFrom(lPerson.Photo);
|
|
|
|
Self.Photo.Position := 0;
|
|
|
|
end
|
|
|
|
else
|
|
|
|
inherited;
|
|
|
|
end;
|
|
|
|
|
2018-09-25 15:36:53 +02:00
|
|
|
constructor TPerson.Create;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
fPhoto := TMemoryStream.Create;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TPerson.Destroy;
|
|
|
|
begin
|
|
|
|
fPhoto.Free;
|
|
|
|
inherited;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TPerson.GetFullName: string;
|
|
|
|
begin
|
|
|
|
Result := fFullName;
|
|
|
|
end;
|
|
|
|
|
2022-10-09 15:45:59 +02:00
|
|
|
function TPerson.GetUniqueString: String;
|
|
|
|
begin
|
|
|
|
Result :=
|
|
|
|
fID.ToString + '|' +
|
|
|
|
fFirstName + '|' +
|
|
|
|
fLastName + '|' +
|
|
|
|
DateToISODate(fDOB.ValueOrDefault) + '|' +
|
|
|
|
BoolToStr(fIsMale.ValueOrDefault, True) + '|' +
|
|
|
|
GetSHA1HashFromStream(fPhoto);
|
|
|
|
end;
|
|
|
|
|
2018-09-25 15:36:53 +02:00
|
|
|
procedure TPerson.OnAfterLoad;
|
|
|
|
begin
|
|
|
|
inherited;
|
2022-08-01 11:18:46 +02:00
|
|
|
if fDOB.HasValue then
|
|
|
|
begin
|
2022-10-25 09:00:35 +02:00
|
|
|
fAge := YearsBetween(fDOB, now);
|
2022-08-01 11:18:46 +02:00
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
fAge.Clear;
|
|
|
|
end;
|
2018-09-25 15:36:53 +02:00
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPerson.OnBeforeInsert;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPerson.OnBeforeInsertOrUpdate;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
fLastName := fLastName.ToUpper;
|
|
|
|
fFirstName := fFirstName.ToUpper;
|
|
|
|
fFullName := fFirstName + ' ' + fLastName;
|
|
|
|
end;
|
|
|
|
|
2020-03-31 20:53:03 +02:00
|
|
|
procedure TPerson.OnValidation(const Action: TMVCEntityAction);
|
2018-09-25 15:36:53 +02:00
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
if fLastName.Trim.IsEmpty or fFirstName.Trim.IsEmpty then
|
2020-10-24 14:21:02 +02:00
|
|
|
raise EMVCActiveRecord.Create
|
|
|
|
('Validation error. FirstName and LastName are required');
|
2018-09-25 15:36:53 +02:00
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPerson.SetLastName(const Value: string);
|
|
|
|
begin
|
|
|
|
fLastName := Value;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPerson.SetNote(const Value: string);
|
|
|
|
begin
|
|
|
|
fNote := Value;
|
|
|
|
end;
|
|
|
|
|
2022-08-01 11:18:46 +02:00
|
|
|
procedure TPerson.SetDOB(const Value: NullableTDate);
|
2018-09-25 15:36:53 +02:00
|
|
|
begin
|
|
|
|
fDOB := Value;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPerson.SetID(const Value: Int64);
|
|
|
|
begin
|
|
|
|
fID := Value;
|
|
|
|
end;
|
|
|
|
|
2022-08-01 11:18:46 +02:00
|
|
|
procedure TPerson.SetIsMale(const Value: NullableBoolean);
|
2018-09-25 15:36:53 +02:00
|
|
|
begin
|
|
|
|
fIsMale := Value;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TPerson.SetFirstName(const Value: string);
|
|
|
|
begin
|
|
|
|
fFirstName := Value;
|
|
|
|
end;
|
|
|
|
|
2018-10-14 18:23:20 +02:00
|
|
|
{ TArticle }
|
|
|
|
|
|
|
|
procedure TArticle.SetDescription(const Value: string);
|
|
|
|
begin
|
|
|
|
FDescription := Value;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TArticle.SetID(const Value: Int64);
|
|
|
|
begin
|
|
|
|
fID := Value;
|
|
|
|
end;
|
|
|
|
|
2021-04-08 00:33:27 +02:00
|
|
|
procedure TArticle.SetPrice(const Value: UInt32);
|
2018-10-14 18:23:20 +02:00
|
|
|
begin
|
|
|
|
FPrice := Value;
|
|
|
|
end;
|
|
|
|
|
2018-10-23 16:18:34 +02:00
|
|
|
{ TPhone }
|
|
|
|
|
2020-03-31 20:53:03 +02:00
|
|
|
procedure TPhone.OnValidation(const Action: TMVCEntityAction);
|
2018-10-23 16:18:34 +02:00
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
if fPhoneNumber.Trim.IsEmpty then
|
|
|
|
raise EMVCActiveRecord.Create('Phone Number cannot be empty');
|
|
|
|
end;
|
|
|
|
|
2020-10-24 14:21:02 +02:00
|
|
|
{ TContact }
|
|
|
|
|
|
|
|
function TContact.GetPhones: TObjectList<TPhone>;
|
|
|
|
begin
|
|
|
|
Result := TMVCActiveRecord.SelectRQL<TPhone>('eq(IDPerson, ' +
|
|
|
|
self.ID.ToString + ')', 100);
|
|
|
|
end;
|
|
|
|
|
2023-09-05 15:27:05 +02:00
|
|
|
{ TSalaryAggregate }
|
|
|
|
|
|
|
|
procedure TSalaryAggregate.SetAverageSalary(const Value: Currency);
|
|
|
|
begin
|
|
|
|
FAverageSalary := Value;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TSalaryAggregate.SetPersonType(const Value: String);
|
|
|
|
begin
|
|
|
|
FPersonType := Value;
|
|
|
|
end;
|
|
|
|
|
2018-09-25 15:36:53 +02:00
|
|
|
initialization
|
|
|
|
|
|
|
|
ActiveRecordMappingRegistry.AddEntity('people', TPerson);
|
2023-09-05 15:27:05 +02:00
|
|
|
ActiveRecordMappingRegistry.AddEntity('salary', TSalaryAggregate);
|
2018-10-23 16:18:34 +02:00
|
|
|
ActiveRecordMappingRegistry.AddEntity('contacts', TContact);
|
|
|
|
ActiveRecordMappingRegistry.AddEntity('phones', TPhone);
|
2018-10-14 18:23:20 +02:00
|
|
|
ActiveRecordMappingRegistry.AddEntity('articles', TArticle);
|
2023-11-27 18:11:49 +01:00
|
|
|
ActiveRecordMappingRegistry.AddEntity('customers', TCustomersWithVersion);
|
2018-09-25 15:36:53 +02:00
|
|
|
|
|
|
|
finalization
|
|
|
|
|
|
|
|
end.
|