Desde de ahora ahora utilizaré la versión Delphi 10.1 Berlín (esta hasta hace poco era, en versión educativa, gratuita). Este año he llegado a realizar un framework casi completo, ahora aplicaremos esa experiencia para realizar uno que intentaremos que sea lo más genérico posible y poder dejarlo totalmente abierto. Ya vimos el uso de los atributos y del uso de JSON, ahora vamos a aplicarlo.
Primero vamos a fijar unos conceptos para la implementación de framework .
- Cada clase será una entidad .
- Podremos usar una una base de datos relacional (BD o BDR) y asociar cada clase con una tabla.
- Cada clase/objeto deberá tener una clave que identifique unívocamente el objeto dentro de la clase, realmente la clave única sera el terna <clase, clave>. En la BD la tabla será la clase y la clave primaria la clave.
- Relacionaremos las propiedades de la clase con los campos de la tabla de la BD.
- Automatizaremos la operaciones (carga, inserción, actualización,...) de los objetos de la clase en función de su clave.
- Usaremos como clase base el tipo TPersistent
- ...Ya Iremos ampliando esta lista...
- ...
Por último especificar que el framework tendrá en nombre de JWD Object Framework y que por tanto las clases empezarán por Tjwd<nombre_clase> y las unidades por jwd.<nombre unidad>, ahora mismo les daremos un nombre, pero seguramente en un futuro refactoricemos y les cambiaremos la nomenclatura..
Empecemos por algo
Iremos creando unidades y las iremos ampliando y creando más. Inicialmente vamos ha crear una unidad jwd.Ground dónde tendremos las clase base que utilizaremos
unit jwd.Ground;
interface
uses
System.Classes;
type
TjwdClass = class of TjwdGroundObject;
TjwdGroundObject = class(TInterfacedPersistent)
public
class function GetJwdClass: TjwdClass; virtual; abstract;
end;
implementation
end.
Ahora una unidad para los interfaces base jwd.Types.Interfaces por ahora crearemos un par interfaces, pero lo iremos ampliando.
unit jwd.Interfaces;
interface
uses
System.Classes, jwd.Ground;
type
IjwdClass = interface
['{2227D866-9D83-48CE-8F4F-D7FBB2E8A3FF}']
function GetJwdIdClass: string;
function GetJwdObject: TjwdGroundObject;
function GetJwdClass: TjwdClass;
property JwdIdClass: string read GetJwdIdClass;
end;
IjwdPersistent = interface
['{0D7C4784-619E-49C7-8B07-5195EEE8217D}']
procedure Assign(Source: TPersistent);
function GetPersistentObject: TPersistent;
end;
implementation
end.
Otra unidad para la clase base jwd.Custom, que seguro que también la ampliamos
unit jwd.Custom;
interface
uses
System.Classes, jwd.Interfaces, jwd.Ground;
type
TjwdCustom = class(TjwdGroundObject, IjwdClass, IjwdPersistent)
protected
// IjwdClass
function GetJwdIdClass: string; virtual;
function GetJwdObject: TjwdGroundObject;
// iherited class function GetJwdClass: TjwdClass;
// IjwdPersistent
function GetPersistentObject: TPersistent;
// Create/Destroy events
protected
procedure BeforeCreate; virtual;
procedure AfterCreate; virtual;
procedure BeforeCreateFrom; virtual;
procedure AfterCreateFrom; virtual;
procedure BeforeDestroy; virtual;
procedure AfterDestroy; virtual;
public
// Clear object
procedure Clear; virtual;
// Object constructors
constructor Create; virtual;
constructor CreateFrom(const AObject: TjwdCustom);
// Object destructor
destructor Destroy; override;
end;
implementation
{ TjwdCustom }
procedure TjwdCustom.AfterCreate;
begin
// for inheritance
end;
procedure TjwdCustom.AfterCreateFrom;
begin
// for inheritance
end;
procedure TjwdCustom.AfterDestroy;
begin
// for inheritance
end;
procedure TjwdCustom.BeforeCreate;
begin
// for inheritance
end;
procedure TjwdCustom.BeforeCreateFrom;
begin
// for inheritance
end;
procedure TjwdCustom.BeforeDestroy;
begin
// for inheritance
end;
procedure TjwdCustom.Clear;
begin
// for inheritance
end;
constructor TjwdCustom.Create;
begin
BeforeCreate;
inherited Create;
Clear;
AfterCreate;
end;
constructor TjwdCustom.CreateFrom(const AObject: TjwdCustom);
begin
BeforeCreateFrom;
Create;
Assign(AObject);
AfterCreateFrom;
end;
destructor TjwdCustom.Destroy;
begin
BeforeDestroy;
inherited;
AfterDestroy;
end;
function TjwdCustom.GetJwdIdClass: string;
begin
Result := GetJwdClass.ClassName;
end;
function TjwdCustom.GetJwdObject: TjwdGroundObject;
begin
Result := Self;
end;
function TjwdCustom.GetPersistentObject: TPersistent;
begin
Result := Self;
end;
end.
También crearemos la unidad para los atributos de clase jwd.Attributes, que cotendra los atributos básicos para enlazar las clases con la BD, más adelante veremos los atributos para las relaciones entre las mismas (1 a 1, 1 a muchos, muchos a muchos)
unit jwd.Attributes;
interface
uses
Data.DB;
type
TjwdAttributes = class(TCustomAttribute);
TjwdDBTableAttr = class(TjwdAttributes)
private
FSchemaName: string;
FTableName: string;
FReadOnly: Boolean;
public
property ReadOnly: Boolean read FReadOnly;
property TableName: string read FTableName;
property SchemaName: string read FSchemaName;
constructor Create(const ATableName: string;
const ASchemaName: string = ''; const AReadOnly: Boolean);
function GetTable(const ATableName, ASchemaName: string): string; overload;
function GetTable: string; overload;
end;
TjwdDBFieldAttr = class(TjwdAttributes)
private
FIsKey: Boolean;
FType: Data.DB.TFieldType;
FSize: Integer;
FFieldName: string;
FVisible: Boolean;
FEditable: Boolean;
public
property FieldName: string read FFieldName;
property DataType: Data.DB.TFieldType read FType;
property Size: integer read FSize;
property IsKey: Boolean read FIsKey;
property Visible: Boolean read FVisible;
property Editable: Boolean read FEditable;
function GetFieldName(const APropertyName: string): string;
constructor Create; overload; virtual;
constructor Create(
const AFieldName: string;
const AFieldType: Data.DB.TFieldType;
const ASize: integer;
const AIsKey: Boolean;
const AVisible: Boolean = True;
const AEditable: Boolean = True
); overload;
constructor Create(
const AFieldType: Data.DB.TFieldType;
const ASize: integer = 0;
const AIsKey: Boolean = False;
const AVisible: Boolean = True;
const AEditable: Boolean = True
); overload;
end;
TjwdDBKeyAttr = class(TjwdDBFieldAttr)
public
constructor Create; overload; override;
constructor Create(
const AFieldName: string;
const AFieldType: Data.DB.TFieldType;
const ASize: integer;
const AVisible: Boolean = True;
const AEditable: Boolean = True); overload;
constructor Create(
const AFieldType: Data.DB.TFieldType;
const ASize: integer = 0;
const AVisible: Boolean = True;
const AEditable: Boolean = True); overload;
end;
implementation
{ TjwdDBTableAttr }
constructor TjwdDBTableAttr.Create(const ATableName, ASchemaName: string;
const AReadOnly: Boolean);
begin
FTableName := ATableName;
FSchemaName := ASchemaName;
FReadOnly := AReadOnly;
end;
function TjwdDBTableAttr.GetTable: string;
begin
Result := GetTable(FTableName, FSchemaName);
end;
function TjwdDBTableAttr.GetTable(const ATableName,
ASchemaName: string): string;
begin
if SchemaName='' then
Result := ASchemaName
else
Result := SchemaName;
if Result<>'' then
Result := Result + '.';
if TableName='' then
Result := Result + TableName
else
Result := Result + ATableName;
end;
{ TjwdDBFieldAttr }
constructor TjwdDBFieldAttr.Create;
begin
Create('', ftUnknown, 0, True, True, False);
end;
constructor TjwdDBFieldAttr.Create(const AFieldName: string;
const AFieldType: Data.DB.TFieldType; const ASize: integer;
const AIsKey, AVisible, AEditable: Boolean);
begin
FFieldName := AFieldName;
FType := AFieldType;
FSize := ASize;
FIsKey := AIsKey;
FVisible := AVisible;
FEditable := AEditable;
end;
constructor TjwdDBFieldAttr.Create(const AFieldType: Data.DB.TFieldType;
const ASize: integer; const AIsKey, AVisible, AEditable: Boolean);
begin
Create('', AFieldType, ASize, AIsKey, AVisible, AEditable);
end;
function TjwdDBFieldAttr.GetFieldName(const APropertyName: string): string;
begin
if FFieldName='' then
Result := APropertyName
else
Result := FFieldName;
end;
{ TjwdDBKeyAttr }
constructor TjwdDBKeyAttr.Create;
begin
inherited Create('', ftUnknown, 0, True, True, True);
end;
constructor TjwdDBKeyAttr.Create(const AFieldName: string;
const AFieldType: Data.DB.TFieldType; const ASize: integer; const AVisible,
AEditable: Boolean);
begin
inherited Create(AFieldName, AFieldType, ASize, AVisible, AEditable, True);
end;
constructor TjwdDBKeyAttr.Create(const AFieldType: Data.DB.TFieldType;
const ASize: integer; const AVisible, AEditable: Boolean);
begin
inherited Create('', AFieldType, ASize, AVisible, AEditable, True);
end;
end.