1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
| {* -----------------------------------------------------------------------------
Thème : Modèle de Persistance (V2)
Unité : Classe de Base des Objets Metiers Persistants
@author ShaiLeTroll
@version 0.7
------------------------------------------------------------------------------ }
unit uEpcPersistance;
(* ATTENTION : le ClassManager ne supporte pas le Multi-Thread *)
// Tester FastMM pour les Fuites Mémoire ...
interface
uses
Windows, SysUtils, Classes, DB, Contnrs, Variants, Math, RTLConsts, Graphics,
uepcDBEntite,
uEpcPersistanceTypes;
type
{*
Type de l'ID d'un Persistant
}
TepcPersistantIDType = Int64;
{*
MétaClasse de TEpcPersistant (Référence de Classe)
}
TEpcPersistantClass = class of TEpcPersistant;
{*
Déclarations avancées de TEpcPersistantCollection
}
TEpcPersistantCollection = class;
{*
Déclarations avancées de TEpcPersistantRelation
}
TEpcPersistantRelation = class;
{*
Une Relation peut être une Clé Etrangère, une Relation N-N, une Relation N-N via une Classe
}
TEpcPersistantRelationType = (prForeignKey, prManyToMany, prObjectRelation);
{*
Déclarations avancées de TEpcPersistantClassList
}
TEpcPersistantClassList = class;
{*
Déclarations avancées de TEpcPersistantClassListItem
}
TEpcPersistantClassListItem = class;
{*
Evènement OnInitialize (voir TEpcPersistantClassManager.DoInitialize)
}
TPersistantInitializeEvent = procedure(const List: TEpcPersistantClassList; const XMLFileName: string; var Accept: Boolean) of Object;
{*
Binone ClassName / ClassType
}
TEpcPersistantRelationDescriptionClass = record
ClassName: ShortString; // voir TObject.ClassName
ClassType: TEpcPersistantClass;
end;
{*
Pointeur sur TEpcPersistantRelationDescription
}
PEpcPersistantRelationDescription = ^TEpcPersistantRelationDescription;
{*
Descripteur de Relation, RelationType prend les Valeurs d'un TEpcPersistantRelationType, LazyLoad indique comment sont fait les lectures de la Base de Données, Detail indique la classe sur laquelle fait la relation pour une ForeignKey, Target indique la classe sur laquelle on devra lire les données issues de la relation extraite de RelationTableName pour une Relation N-N (ManyToMany), FirstRelationPart et SecondRelationPart se comporte comme une Double ForeignKey dans le Cas d'une Relation N-N via Classe sans se préoccuper de celle-ci
}
TEpcPersistantRelationDescription = record
RelationType: TEpcPersistantRelationType;
LazyLoad: Boolean;
case TEpcPersistantRelationType of
prForeignKey:
(
Detail: TEpcPersistantRelationDescriptionClass;
);
prManyToMany:
(
Target: TEpcPersistantRelationDescriptionClass;
RelationTableName: string[255];
);
prObjectRelation:
(
FirstRelationPart: TEpcPersistantRelationDescriptionClass;
SecondRelationPart: TEpcPersistantRelationDescriptionClass;
);
end;
{*
Contient les Données d'une Propriété Publiée
}
TEpcPersistantPropertyData = record
OldValue: Variant;
NewValue: Variant;
PropertyType: Pointer; // via la Function TypeInfo(...);
Changed: Boolean;
Name: string;
end;
TEpcPersistantPropertyDataList = array of TEpcPersistantPropertyData;
{*
Classe de Base de Tous composants Persistants dans une Application Censure sur le Modèle de Persistance V2
}
TEpcPersistant = class(TComponent)
private
{ Membres Privés }
FTableName: string; /// Champ Interne, cf TableName
FID: TepcPersistantIDType; /// Champ Interne, cf ID
FIDName: string; /// Champ Interne, cf IDName
FRelations: array of TEpcPersistantRelation; /// Champ Interne, cf Relations
FRelationsToDo: TList;
FData: TEpcPersistantPropertyDataList;
FCollection: TEpcPersistantCollection;
{ Méthodes Privés }
procedure _Initialize();
procedure _Finalize();
function AddRelationToDo(const RelationTableName: string; Master: TEpcPersistant; out ToDo: Pointer): Boolean;
function AddRelationToSave(const RelationTableName: string; Master: TEpcPersistant): Boolean; overload;
function AddRelationToSave(Relation, Master: TEpcPersistant): Boolean; overload;
function AddRelationToDelete(const RelationTableName: string; Master: TEpcPersistant): Boolean;
function AlterRelation(): Boolean;
procedure InternalLoad(const NewID: TepcPersistantIDType);
procedure InternalSave();
function GetPropertyIndex(const PropertyName: string): Integer;
function GetPropertyName(const Index: Integer): string;
function GetPropertyData(const PropertyName: string): TEpcPersistantPropertyData;
function RemoveCollection(): TEpcPersistantCollection;
class function CreateCollection(): TEpcPersistantCollection;
class function GetRelationDescription(const PersistantClass: TEpcPersistantClass): PEpcPersistantRelationDescription;
class procedure CleanComponentProperties(List: TStrings);
protected
{ Méthodes d'Accès }
function GetItSelf(): TEpcPersistant;
function GetPersistantClass: TEpcPersistantClass;
function GetPersistantClassName: string;
function GetRelations(const PersistantClass: TEpcPersistantClass): TEpcPersistantRelation;
function GetPublishedProperty(const PropertyName: string): Variant;
procedure SetPublishedProperty(const PropertyName: string; Value: Variant);
function GetPublishedPropertyIsNull(const PropertyName: string): Boolean;
function GetPublishedPropertyChanged( const PropertyName: string): Boolean;
function GetPublishedPropertyType(const PropertyName: string): Pointer;
function GetPublishedPropertyVarType(const PropertyName: string): TVarType;
function GetIsAncestorClass: Boolean;
function GetChanged: Boolean;
{ Méthodes d'Accès pour les Propriétés Indicées }
function GetData(const Index: Integer): Variant; virtual;
procedure SetData(const Index: Integer; const Value: Variant); virtual;
{ Propriétés Protégées }
property Data[const Index : Integer]: Variant read GetData write SetData;
{ Propriétés Protégées à Publier !}
property Relations[const PersistantClass: TEpcPersistantClass]: TEpcPersistantRelation read GetRelations;
public
{ Constructeurs }
constructor Create(AOwner: TComponent); overload; override;
constructor Create(); reintroduce; overload; virtual;
destructor Destroy; override; /// Destructeur surchargé d'un TComponent
{ Méthodes Publiques }
procedure Assign(Source: TPersistent); overload; override;
procedure Assign(Source: TPersistent; const Exclude: TStrings); reintroduce; overload; virtual;
procedure AssignTo(Dest: TPersistent); overload; override;
procedure AssignTo(Dest: TPersistent; const Exclude: TStrings); reintroduce; overload; virtual;
class function Active: Boolean;
class procedure RegisterMe();
class function IsDebugger(): Boolean;
class function Initialize(const XMLFileName: string; const OnInitialize: TPersistantInitializeEvent = nil): Boolean;
class function InitializeBooleanValues(LocalIndex: Integer; const ATrueBoolStrs: array of string; const AFalseBoolStrs: array of string): Boolean;
class function FindHerited(const ClassName: string): TEpcPersistantClass;
class function PropertyCount: Integer;
class function GetProperties(List: TStrings): Boolean;
class function IsPublishedProperty(const PropertyName: string): Boolean;
class function Load(const ID: TepcPersistantIDType): TEpcPersistant; overload;
class function Load(const Keys: array of string; const Values: array of Variant): TEpcPersistant; overload;
class function Load(Location: TPersistantProcLocation; const ProcName: string; const Values: array of const): TEpcPersistant; overload;
class function Select(const Keys: array of string; const Values: array of Variant; OnlyOne: Boolean = False): TEpcPersistantCollection; overload;
class function Select(const Keys: array of string; const Values: array of Variant; OnlyOne: Boolean; const Operators: array of TRelationalOperatorType): TEpcPersistantCollection; overload;
class function Select(Location: TPersistantProcLocation; const ProcName: string; const Values: array of const; Index: Integer = 1; OnlyOne: Boolean = False): TEpcPersistantCollection; overload;
function Fill(const Data: TDataSet): Boolean;
function Save(): Boolean;
function Delete(Cascade: Boolean = False): Boolean;
function ToComponentString(): string;
class function ComponentStringTo(Value: string): TEpcPersistant;
class function RealAssigned(var Obj): Boolean;
function StringToProperty(const PropertyName: string; const Value: string): Variant;
function PropertyToString(const PropertyName: string): string;
{ Propriétés Publiques }
property ItSelf: TEpcPersistant read GetItSelf;
property TableName: string read FTableName; /// Nom de la Table Associée aux Persistants
property ID: TepcPersistantIDType read FID; /// Identifiant Clé Primaire AutoIncrémenté Unique
property IDName: string read FIDName; /// Nom de la Clé Primaire normalement "ID_TableName"
property PersistantClass: TEpcPersistantClass read GetPersistantClass; /// Classe du Persistant
property PropertyName[const Index: Integer]: string read GetPropertyName;
property PublishedProperty[const PropertyName: string]: Variant read GetPublishedProperty write SetPublishedProperty;
property PublishedPropertyIsNull[const PropertyName: string]: Boolean read GetPublishedPropertyIsNull;
property PublishedPropertyChanged[const PropertyName: string]: Boolean read GetPublishedPropertyChanged;
property PublishedPropertyType[const PropertyName: string]: Pointer read GetPublishedPropertyType;
property PublishedPropertyVarType[const PropertyName: string]: TVarType read GetPublishedPropertyVarType;
property IsAncestorClass: Boolean read GetIsAncestorClass; /// Classe utilisée comme Ancêtre ?
property Changed: Boolean read GetChanged;
published
{ Propriétés Publiées }
property PersistantClassName: string read GetPersistantClassName; /// cf constante FIELD_CLASS_NAME
end;
{*
Classe pour Lister d'Objets Persistants sous la Forme d'une Collection
}
TEpcPersistantCollection = class(TComponent)
private
{ Membres Privés }
FDataSet: TDataSet; /// DataSet Contenant les Objets
FDataSource: TDataSource; /// DataSource pour afficher le DataSet
FTableName: string; /// Identifie la Table sur laquelle la lecture des Objets a été faites
FIDName: string; /// Identifie la Clé Primaire de la Table sur laquelle la lecture des Objets a été faites
FDefaultClass: TEpcPersistantClass; /// Identifie la Classe par Défaut si le DataSet ne contient pas le Champ nommé FIELD_CLASS_NAME
FPersistantList: TList;
function CreateDefault(): TEpcPersistant;
procedure ClearPersistantList();
procedure NotifyDelete(const Persistant: TepcPersistant);
protected
{ Méthodes d'Accès }
procedure SetDataSet(Value: TDataSet); virtual;
function GetIsEmpty(): Boolean; virtual;
function GetCount(): Integer; virtual;
function GetBOF(): Boolean; virtual;
function GetEOF(): Boolean; virtual;
function GetPersistant(): TEpcPersistant; virtual;
function GetDataSource: TDataSource; virtual;
function GetItems(Index: Integer): TEpcPersistant; virtual;
{ Méthodes Protégées }
function GetPersistantOverload(RecNo: Integer): TEpcPersistant;
procedure SetPersistantOverload(RecNo: Integer; var Value: TEpcPersistant);
{ Propriétés Protégées }
property DataSet: TDataSet read FDataSet write SetDataSet; /// La Collection devient le Owner du DataSet !!!
property TableName: string read FTableName write FTableName; /// Table correspond au DataSet
property IDName: string read FIDName write FIDName; /// Clé Primaire de la Table correspond au DataSet
public
{ Constructeurs }
constructor Create(AOwner: TComponent); override;
destructor Destroy(); override;
{ Méthodes Publiques }
procedure First(); virtual;
procedure Last(); virtual;
procedure Next(); virtual;
procedure Prior(); virtual;
procedure Delete(); overload; virtual;
function Delete(const Persistant: TEpcPersistant): Boolean; overload; virtual;
procedure Clear(); virtual;
function Locate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): Boolean; overload;
function Locate(const Keys: array of string; const Values: array of Variant; Options: TLocateOptions): Boolean; overload;
function Locate(const ID: TepcPersistantIDType): Boolean; overload;
function Load(const ID: TepcPersistantIDType): TEpcPersistant; virtual;
function ChangeFieldNames(const Names: array of string; const Labels: array of string): Boolean;
{ Propriétés Publiques }
property IsEmpty: Boolean read GetIsEmpty; /// Détermine si un ensemble de données ne contient pas d'enregistrement.
property Count: Integer read GetCount; /// Nombre de Persistant
property BOF: Boolean read GetBOF; /// Début du DataSet
property EOF: Boolean read GetEOF; /// Fin du DataSet
property Persistant: TEpcPersistant read GetPersistant; /// Ligne Courante du DataSet converti en TepcPersistant
property Items[Index: Integer]: TEpcPersistant read GetItems; default; /// Element de la Collection
property DataSource: TDataSource read GetDataSource; /// Founit le DataSource qui consultera le DataSet Interne pour une Vue Grille
property DefaultClass: TEpcPersistantClass read FDefaultClass write FDefaultClass; /// Indique le DataSource qui consultera le DataSet Interne pour une Vue Grille
end;
{*
Classe pour Lier des Classes d'Objets Persistants
}
TEpcPersistantRelation = class(TEpcPersistantCollection)
private
{ Membres Privés }
FPersistantMaster: TEpcPersistant; /// Champ Interne, cf PersistantMaster
FPersistantClass: TEpcPersistantClass; /// Champ Interne, cf PersistantClass
FRD: PEpcPersistantRelationDescription; /// Champ Interne, contient la Description de la Relation
FRelationLoaded: Boolean; /// Champ Interne, cf RelationLoaded
FLazyLoaded: Boolean; /// Champ Interne, cf LazyLoaded
FTheoricCount: Integer; /// Champ Interne, cf Count
FRelationCountMode: Boolean; /// Champ Interne, cf Count
procedure BeginRelationCount();
procedure EndRelationCount();
protected
{ Méthodes d'Accès }
function GetCount(): Integer; override;
function GetPersistant(): TEpcPersistant; override; // Attention à ceci !
function GetDataSource: TDataSource; override;
{ Méthodes Protégées }
public
{ Constructeurs }
constructor Create(AOwner: TComponent); overload; override;
constructor Create(const APersistantMaster: TEpcPersistant; const APersistantClass: TEpcPersistantClass); reintroduce; overload; virtual;
{ Méthodes Publiques }
procedure First(ActionReload: Boolean = False); reintroduce; overload; virtual;
procedure Last(ActionReload: Boolean = False); reintroduce; overload; virtual;
function Load(const ID: TepcPersistantIDType): TEpcPersistant; overload; override;
function Load(ActionFirst: Boolean = True; FullLoad: Boolean = False): TEpcPersistantRelation; reintroduce; overload; virtual;
function Add(const Persistant: TEpcPersistant; const Relation: TEpcPersistant = nil): Boolean;
function Delete(const Persistant: TEpcPersistant): Boolean; override;
function Delete(): Boolean; reintroduce; overload; virtual;
procedure Clear(); override;
{ Propriétés Publiques }
property PersistantMaster: TEpcPersistant read FPersistantMaster; /// Identifie l'Instance de l'Objet Persistant à partir duquel on a extrait les Relations
property PersistantClass: TEpcPersistantClass read FPersistantClass; /// Identifie la Classe Ancêtre des Objets extraits de la Relation
property RelationLoaded: Boolean read FRelationLoaded; /// Indique que la Relation a au moins été chargé une fois
property LazyLoaded: Boolean read FLazyLoaded; /// Indique que la Relation ne contient que les ID et non l'ensemble des Données
end;
{*
Classe qui reprend l'ensemble des informations des Classes décrites dans le XML de Classes
}
TEpcPersistantClassList = class(TObjectList)
public
function IndexOf(const PersistantClass: TEpcPersistantClass): Integer;
end;
{*
Classe qui reprend les informations des Classes décrites dans le XML de Classes, Correspond à un Element d'une TEpcPersistantClassList
}
TEpcPersistantClassListItem = class(TObject)
private
FTableName: string; /// Champ Interne, cf TableName
FIsAncestorClass: Boolean; /// Champ Interne, cf IsAncestorClass
FPersistantClass: TEpcPersistantClass; /// Champ Interne, cf PersistantClass
FPersistantClassName: string; /// Champ Interne, cf PersistantClassName
FProperties: TStrings; /// Champ Interne, cf Properties
FRelationDescriptions: TList; /// Champ Interne, cf RelationDescriptions
FPropertyData: TEpcPersistantPropertyDataList;
public
{ Constructeurs }
constructor Create();
destructor Destroy(); override;
{ Méthodes Publiques }
procedure Initialize(); overload;
procedure Initialize(Persistant: TEpcPersistant); overload;
procedure Finalize(Persistant: TEpcPersistant);
{ Propriétés Publiques }
property TableName: string read FTableName write FTableName; /// Nom de la Table associé à un Persistant décrit le Fichier XML
property IsAncestorClass: Boolean read FIsAncestorClass write FIsAncestorClass; // Indique si la Classe possède des Classes Heritées
property PersistantClass: TEpcPersistantClass read FPersistantClass write FPersistantClass; // Classe du Persistant
property PersistantClassName: string read FPersistantClassName write FPersistantClassName; // Nom de la Classe du Persistant décrit le Fichier XML
property Properties: TStrings read FProperties; /// Liste des Proprités d'une Classe lue dans le Fichier XML
property RelationDescriptions: TList read FRelationDescriptions; /// Liste des Relations d'une Classe Persistante décrites le Fichier XML
end; |
Partager