1 | unit UDatabase;
|
---|
2 |
|
---|
3 | {$mode delphi}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | SysUtils, Variants, Classes, TypInfo, USqlDatabase, RTLConsts, Contnrs, Dialogs;
|
---|
9 |
|
---|
10 | type
|
---|
11 | TDatabase = class;
|
---|
12 | TDbList = class;
|
---|
13 | TDbListClass = class of TDbList;
|
---|
14 | TDbObject = class;
|
---|
15 | TDbObjectClass = class of TDbObject;
|
---|
16 |
|
---|
17 | {$M+}
|
---|
18 | TDbObject = class
|
---|
19 | private
|
---|
20 | FDatabase: TDatabase;
|
---|
21 | FId: Integer;
|
---|
22 | FRow: TAssociativeArray;
|
---|
23 | procedure WriteProperty(Instance: TDbObject; PropInfo: PPropInfo; Data: TAssociativeArray; Depth: Integer);
|
---|
24 | procedure DeleteProperty(Instance: TDbObject; PropInfo: PPropInfo);
|
---|
25 | procedure DestroyProperty(Instance: TDbObject; PropInfo: PPropInfo; Depth: Integer);
|
---|
26 | procedure ReadProperty(Instance: TObject; PropInfo: PPropInfo; Data: TAssociativeArray; Depth: Integer);
|
---|
27 | function SearchPropertyByPointer(P: Pointer): string;
|
---|
28 | public
|
---|
29 | constructor Create(ADatabase: TDatabase); virtual;
|
---|
30 | procedure Init;
|
---|
31 | procedure Store(Depth: Integer = 1); virtual;
|
---|
32 | procedure Delete;
|
---|
33 | procedure LoadById(Id: Integer; Depth: Integer = 1);
|
---|
34 | procedure Load(Depth: Integer = 1);
|
---|
35 | procedure LoadFromRow(Row: TAssociativeArray; Depth: Integer = 1);
|
---|
36 | destructor Destroy(Depth: Integer = 100); virtual;
|
---|
37 | property Database: TDatabase read FDatabase write FDatabase;
|
---|
38 | published
|
---|
39 | property Id: Integer read FId write Fid;
|
---|
40 | end;
|
---|
41 |
|
---|
42 | // TList with RTTI information
|
---|
43 | TPersistentList = class
|
---|
44 | private
|
---|
45 | FList: PPointerList;
|
---|
46 | FCount: Integer;
|
---|
47 | FCapacity: Integer;
|
---|
48 | protected
|
---|
49 | function Get(Index: Integer): Pointer;
|
---|
50 | procedure Grow; virtual;
|
---|
51 | procedure Put(Index: Integer; Item: Pointer);
|
---|
52 | procedure Notify(Ptr: Pointer; Action: TListNotification); virtual;
|
---|
53 | procedure SetCapacity(NewCapacity: Integer);
|
---|
54 | procedure SetCount(NewCount: Integer);
|
---|
55 | public
|
---|
56 | destructor Destroy; override;
|
---|
57 | function Add(Item: Pointer): Integer;
|
---|
58 | procedure Clear; virtual;
|
---|
59 | procedure Delete(Index: Integer);
|
---|
60 | class procedure Error(const Msg: string; Data: Integer); overload; virtual;
|
---|
61 | class procedure Error(Msg: PResStringRec; Data: Integer); overload;
|
---|
62 | procedure Exchange(Index1, Index2: Integer);
|
---|
63 | function Expand: TPersistentList;
|
---|
64 | function Extract(Item: Pointer): Pointer;
|
---|
65 | function First: Pointer;
|
---|
66 | function IndexOf(Item: Pointer): Integer;
|
---|
67 | procedure Insert(Index: Integer; Item: Pointer);
|
---|
68 | function Last: Pointer;
|
---|
69 | procedure Move(CurIndex, NewIndex: Integer);
|
---|
70 | function Remove(Item: Pointer): Integer;
|
---|
71 | procedure Pack;
|
---|
72 | procedure Sort(Compare: TListSortCompare);
|
---|
73 | procedure Assign(ListA: TPersistentList; AOperator: TListAssignOp = laCopy; ListB: TPersistentList = nil);
|
---|
74 | property Capacity: Integer read FCapacity write SetCapacity;
|
---|
75 | property Count: Integer read FCount write SetCount;
|
---|
76 | property Items[Index: Integer]: Pointer read Get write Put; default;
|
---|
77 | property List: PPointerList read FList;
|
---|
78 | end;
|
---|
79 |
|
---|
80 | TDbList = class(TObjectList)
|
---|
81 | private
|
---|
82 | FId: Integer;
|
---|
83 | FItemId: Integer;
|
---|
84 | FDatabase: TDatabase;
|
---|
85 | FItemsClass: TDbObjectClass;
|
---|
86 | procedure Put(Index: Integer; const Value: TDbObject); virtual;
|
---|
87 | function Get(Index: Integer): TDbObject; virtual;
|
---|
88 | procedure CheckId;
|
---|
89 | public
|
---|
90 | procedure Store(Depth: Integer = 1);
|
---|
91 | procedure Load(Depth: Integer = 1);
|
---|
92 | procedure Delete;
|
---|
93 | constructor Create(ADatabase: TDatabase; Id: Integer); virtual;
|
---|
94 | destructor Destroy(Depth: Integer = 100);
|
---|
95 | // property Id: Integer read FId write Fid;
|
---|
96 | property Items[Index: Integer]: TDbObject read Get write Put; default;
|
---|
97 | property ItemsClass: TDbObjectClass read FItemsClass write FItemsClass;
|
---|
98 | published
|
---|
99 | property ListId: Integer read FId write Fid;
|
---|
100 | property ItemId: Integer read FItemId write FItemId;
|
---|
101 | end;
|
---|
102 | {$M-}
|
---|
103 |
|
---|
104 | TDatabase = class(TSqlDatabase)
|
---|
105 | private
|
---|
106 | FOnError: TNotifyEvent;
|
---|
107 | procedure HandleError(Sender: TObject);
|
---|
108 | public
|
---|
109 | ProcessedClass: TObject;
|
---|
110 | DbObject: TDbObject;
|
---|
111 | constructor Create;
|
---|
112 | property OnError: TNotifyEvent read FOnError write FOnError;
|
---|
113 | procedure CheckTable;
|
---|
114 | destructor Destroy; override;
|
---|
115 | end;
|
---|
116 |
|
---|
117 | procedure LogMessage(Text: string);
|
---|
118 |
|
---|
119 | implementation
|
---|
120 |
|
---|
121 | procedure LogMessage(Text: string);
|
---|
122 | begin
|
---|
123 |
|
---|
124 | end;
|
---|
125 |
|
---|
126 | { TDbObject }
|
---|
127 |
|
---|
128 | procedure TDbObject.WriteProperty(Instance: TDbObject; PropInfo: PPropInfo; Data: TAssociativeArray; Depth: Integer);
|
---|
129 | var
|
---|
130 | PropType: PTypeInfo;
|
---|
131 | // AncestorValid: Boolean;
|
---|
132 |
|
---|
133 | procedure WriteSet(Value: Longint);
|
---|
134 | // var
|
---|
135 | // I: Integer;
|
---|
136 | // BaseType: PTypeInfo;
|
---|
137 | begin
|
---|
138 | (*
|
---|
139 | BaseType := GetTypeData(PropType)^.CompType^;
|
---|
140 | WriteValue(vaSet);
|
---|
141 | for I := 0 to SizeOf(TIntegerSet) * 8 - 1 do
|
---|
142 | if I in TIntegerSet(Value) then WriteStr(GetEnumName(BaseType, I));
|
---|
143 | WriteStr('');
|
---|
144 | *)
|
---|
145 | end;
|
---|
146 |
|
---|
147 | procedure WriteIntProp(IntType: PTypeInfo; Value: Longint);
|
---|
148 | var
|
---|
149 | Ident: string;
|
---|
150 | IntToIdent: TIntToIdent;
|
---|
151 | begin
|
---|
152 | IntToIdent := FindIntToIdent(IntType);
|
---|
153 | if Assigned(IntToIdent) and IntToIdent(Value, Ident) then
|
---|
154 | //WriteIdent(Ident)
|
---|
155 | else
|
---|
156 | Data.AddKeyValue(PropInfo.Name, IntToStr(Value));
|
---|
157 | end;
|
---|
158 |
|
---|
159 | procedure WriteOrdProp;
|
---|
160 | var
|
---|
161 | Value: Longint;
|
---|
162 | begin
|
---|
163 | Value := GetOrdProp(Instance, PropInfo);
|
---|
164 | case PropType^.Kind of
|
---|
165 | tkInteger:
|
---|
166 | WriteIntProp(PPropInfo(PropInfo)^.PropType, Value);
|
---|
167 | tkChar:
|
---|
168 | Data.AddKeyValue(PropInfo.Name, Chr(Value));
|
---|
169 | tkSet:
|
---|
170 | LogMessage('Unsupported writer persistent type: Set');
|
---|
171 | // WriteSet(Value);
|
---|
172 | tkEnumeration:
|
---|
173 | Data.AddKeyValue(PropInfo.Name, IntToStr(Value));
|
---|
174 | end;
|
---|
175 | end;
|
---|
176 |
|
---|
177 | procedure WriteFloatProp;
|
---|
178 | var
|
---|
179 | Value: Extended;
|
---|
180 | begin
|
---|
181 | Value := GetFloatProp(Instance, PropInfo);
|
---|
182 | Data.AddKeyValue(PropInfo.Name, MysqlFloatToStr(Value));
|
---|
183 | end;
|
---|
184 |
|
---|
185 | procedure WriteInt64Prop;
|
---|
186 | // var
|
---|
187 | // Value: Int64;
|
---|
188 | begin
|
---|
189 | (*
|
---|
190 | Value := GetInt64Prop(Instance, PropInfo);
|
---|
191 | WritePropPath;
|
---|
192 | WriteInteger(Value);
|
---|
193 | *)
|
---|
194 | end;
|
---|
195 |
|
---|
196 | procedure WriteStrProp;
|
---|
197 | begin
|
---|
198 | Data.AddKeyValue(PropInfo.Name, GetWideStrProp(Instance, PropInfo));
|
---|
199 | end;
|
---|
200 |
|
---|
201 | procedure WriteObjectProp;
|
---|
202 | var
|
---|
203 | Value: TObject;
|
---|
204 | // OldAncestor: TPersistent;
|
---|
205 | // SavePropPath, ComponentValue: string;
|
---|
206 | begin
|
---|
207 | Value := TObject(GetOrdProp(Instance, PropInfo));
|
---|
208 | if Value = nil then begin
|
---|
209 | Data.AddKeyValue(PropInfo.Name, IntToStr(0));
|
---|
210 | end else if Value is TDbObject then begin
|
---|
211 | TDbObject(Value).Store(Depth-1);
|
---|
212 | Data.AddKeyValue(PropInfo.Name, IntToStr(TDbObject(Value).Id));
|
---|
213 | end else if Value is TDbList then begin
|
---|
214 | if Value = nil then raise Exception.Create('WriteObjectProp: Unbelievable! Value is nil!');
|
---|
215 | TDbList(Value).Store(Depth-1);
|
---|
216 | Data.AddKeyValue(PropInfo.Name, IntToStr(TDbList(Value).FId));
|
---|
217 | end;
|
---|
218 | end;
|
---|
219 |
|
---|
220 |
|
---|
221 | begin
|
---|
222 | // Using IsDefaultPropertyValue will tell us if we should write out
|
---|
223 | // a given property because it was different from the default or
|
---|
224 | // different from the Ancestor (if applicable).
|
---|
225 | if (PropInfo^.GetProc <> nil) and
|
---|
226 | ((PropInfo^.SetProc <> nil) or
|
---|
227 | ((PropInfo^.PropType^.Kind = tkClass) and
|
---|
228 | (TObject(GetOrdProp(Instance, PropInfo)) is TComponent) and
|
---|
229 | (csSubComponent in TComponent(GetOrdProp(Instance, PropInfo)).ComponentStyle))) then
|
---|
230 | begin
|
---|
231 | LogMessage('Write property: '+Instance.ClassName+'.'+PropInfo.Name);
|
---|
232 | //if not IsDefaultPropertyValue(Instance, PropInfo, GetLookupInfo) then
|
---|
233 | begin
|
---|
234 | //AncestorValid := AncestorIsValid(Ancestor, Root, RootAncestor);
|
---|
235 | PropType := PropInfo^.PropType;
|
---|
236 | case PropType^.Kind of
|
---|
237 | tkInteger, tkChar, tkEnumeration, tkSet:
|
---|
238 | WriteOrdProp;
|
---|
239 | tkFloat:
|
---|
240 | WriteFloatProp;
|
---|
241 | tkString, tkLString, tkWString:
|
---|
242 | WriteStrProp;
|
---|
243 | tkClass:
|
---|
244 | WriteObjectProp;
|
---|
245 | //tkMethod:
|
---|
246 | // WriteMethodProp;
|
---|
247 | //tkVariant:
|
---|
248 | // WriteVariantProp;
|
---|
249 | tkInt64:
|
---|
250 | WriteInt64Prop;
|
---|
251 | //tkInterface:
|
---|
252 | // WriteInterfaceProp;
|
---|
253 | else
|
---|
254 | raise Exception.Create('Not supported class property '+GetEnumName(PropType, Integer(PropType^.Kind)));
|
---|
255 | end;
|
---|
256 | end;
|
---|
257 | end;
|
---|
258 | end;
|
---|
259 |
|
---|
260 |
|
---|
261 | procedure TDbObject.ReadProperty(Instance: TObject; PropInfo: PPropInfo; Data: TAssociativeArray; Depth: Integer);
|
---|
262 | const
|
---|
263 | NilMethod: TMethod = (Code: nil; Data: nil);
|
---|
264 | var
|
---|
265 | PropType: PTypeInfo;
|
---|
266 | // Method: TMethod;
|
---|
267 |
|
---|
268 | procedure SetIntIdent(Instance: TPersistent; PropInfo: Pointer;
|
---|
269 | const Ident: string);
|
---|
270 | var
|
---|
271 | V: Longint;
|
---|
272 | IdentToInt: TIdentToInt;
|
---|
273 | begin
|
---|
274 | IdentToInt := FindIdentToInt(PPropInfo(PropInfo)^.PropType);
|
---|
275 | if Assigned(IdentToInt) and IdentToInt(Ident, V) then
|
---|
276 | SetOrdProp(Instance, PropInfo, V)
|
---|
277 | else
|
---|
278 | //PropValueError;
|
---|
279 | end;
|
---|
280 |
|
---|
281 | procedure ProcessObjectProp;
|
---|
282 | var
|
---|
283 | Setter: Longint;
|
---|
284 | Value: TObject;
|
---|
285 | TypeData: PTypeData;
|
---|
286 | TargetObject: ^TObject;
|
---|
287 | TargetClass: TClass;
|
---|
288 | DbListClass: TDbListClass;
|
---|
289 | DbObjectClass: TDbObjectClass;
|
---|
290 | begin
|
---|
291 | if Depth > 0 then begin
|
---|
292 | // List := TDbList.Create(AClass, FDatabase, FId);
|
---|
293 | Value := TObject(GetOrdProp(Instance, PropInfo));
|
---|
294 | TypeData := GetTypeData(PropInfo.PropType);
|
---|
295 | // ShowMessage(PropInfo.Name+' '+TypeData.ClassType.ClassName);
|
---|
296 | if Value = nil then begin
|
---|
297 | Setter := Longint(PropInfo^.SetProc);
|
---|
298 | if (Setter and $FF000000) = $FF000000 then
|
---|
299 | begin // field - Setter is the field's offset in the instance data
|
---|
300 | TargetObject := Pointer(Integer(Instance) + (Setter and $00FFFFFF));
|
---|
301 | TargetClass := TypeData.ClassType;
|
---|
302 | // TargetClass := TargetClass.ClassParent;
|
---|
303 | // ShowMessage(TargetClass.ClassName);
|
---|
304 | if TargetClass.ClassParent = TDbObject then begin
|
---|
305 | DbObjectClass := TDbObjectClass(TargetClass);
|
---|
306 | TargetObject^ := DbObjectClass.Create(FDatabase); // auto ref count
|
---|
307 | end else
|
---|
308 | if TargetClass.ClassParent = TDbList then begin
|
---|
309 | DbListClass := TDbListClass(TargetClass);
|
---|
310 | //ShowMessage(DbListClass.ClassName);
|
---|
311 |
|
---|
312 | TargetObject^ := DbListClass.Create(FDatabase, StrToInt(FRow.Values[PropInfo.Name])); // auto ref count
|
---|
313 | end else TargetObject^ := TargetClass.Create; // auto ref count
|
---|
314 | Value := TObject(GetOrdProp(Instance, PropInfo));
|
---|
315 | end else raise Exception.Create('Object property '+PropInfo.Name+' in object '+Instance.ClassName+' is not mapped directly to variable!');
|
---|
316 | end;
|
---|
317 | //ShowMessage(IntToStr(Integer(Value.ClassInfo)));
|
---|
318 | if Value is TDbObject then begin
|
---|
319 | (Value as TDbObject).LoadById(StrToInt(FRow.Values[PropInfo.Name]), Depth-1);
|
---|
320 | //ShowMessage(Value.ClassName);
|
---|
321 | end else if Value is TDbList then begin
|
---|
322 | (Value as TDbList).Load(Depth);
|
---|
323 | //ShowMessage(Value.ClassName);
|
---|
324 | end;
|
---|
325 | end;
|
---|
326 | end;
|
---|
327 |
|
---|
328 | begin
|
---|
329 | LogMessage('Read property: ' + Instance.ClassName + '.' + PropInfo.Name);
|
---|
330 | // if PPropInfo(PropInfo)^.SetProc = nil then
|
---|
331 | // if not ((PPropInfo(PropInfo)^.PropType^.Kind = tkClass) and
|
---|
332 | // (TObject(GetOrdProp(Instance, PropInfo)) is TComponent) and
|
---|
333 | // (csSubComponent in TComponent(GetOrdProp(Instance, PropInfo)).ComponentStyle)) then
|
---|
334 | // ReadError(@SReadOnlyProperty);
|
---|
335 | PropType := PPropInfo(PropInfo)^.PropType;
|
---|
336 | try
|
---|
337 | case PropType^.Kind of
|
---|
338 | tkInteger:
|
---|
339 | // if NextValue = vaIdent then
|
---|
340 | // SetIntIdent(Instance, PropInfo, Data)
|
---|
341 | // else
|
---|
342 | SetOrdProp(Instance, PropInfo, StrToInt(Data.Values[PropInfo.Name]));
|
---|
343 | tkChar:
|
---|
344 | SetOrdProp(Instance, PropInfo, Ord(Data.Values[PropInfo.Name][1]));
|
---|
345 | tkEnumeration:
|
---|
346 | SetOrdProp(Instance, PropInfo, StrToInt(Data.Values[PropInfo.Name]));
|
---|
347 | tkFloat:
|
---|
348 | SetFloatProp(Instance, PropInfo, MySqlStrToFloat(Data.Values[PropInfo.Name]));
|
---|
349 | tkString, tkLString:
|
---|
350 | SetStrProp(Instance, PropInfo, Data.Values[PropInfo.Name]);
|
---|
351 | tkWString:
|
---|
352 | SetWideStrProp(Instance, PropInfo, Data.Values[PropInfo.Name]);
|
---|
353 | tkSet:
|
---|
354 | LogMessage('Unsupported reader property type: Set');
|
---|
355 | //SetOrdProp(Instance, PropInfo, ReadSet(PropType));
|
---|
356 | tkClass: ProcessObjectProp;
|
---|
357 | (*
|
---|
358 | case NextValue of
|
---|
359 | vaNil:
|
---|
360 | begin
|
---|
361 | ReadValue;
|
---|
362 | SetOrdProp(Instance, PropInfo, 0);
|
---|
363 | end;
|
---|
364 | vaCollection:
|
---|
365 | begin
|
---|
366 | ReadValue;
|
---|
367 | ReadCollection(TCollection(GetOrdProp(Instance, PropInfo)));
|
---|
368 | end
|
---|
369 | else
|
---|
370 | SetObjectIdent(Instance, PropInfo, ReadIdent);
|
---|
371 | end;
|
---|
372 | *)
|
---|
373 | (* tkMethod:
|
---|
374 | if NextValue = vaNil then
|
---|
375 | begin
|
---|
376 | ReadValue;
|
---|
377 | SetMethodProp(Instance, PropInfo, NilMethod);
|
---|
378 | end
|
---|
379 | else
|
---|
380 | begin
|
---|
381 | Method.Code := FindMethod(Root, ReadIdent);
|
---|
382 | Method.Data := Root;
|
---|
383 | if Method.Code <> nil then SetMethodProp(Instance, PropInfo, Method);
|
---|
384 | end;
|
---|
385 | tkVariant:
|
---|
386 | SetVariantReference;
|
---|
387 | tkInt64:
|
---|
388 | SetInt64Prop(Instance, PropInfo, ReadInt64);
|
---|
389 | tkInterface:
|
---|
390 | SetInterfaceReference;
|
---|
391 | *)
|
---|
392 | end;
|
---|
393 | finally
|
---|
394 | end;
|
---|
395 | end;
|
---|
396 |
|
---|
397 | procedure TDbObject.Init;
|
---|
398 | begin
|
---|
399 | end;
|
---|
400 |
|
---|
401 | destructor TDbObject.Destroy(Depth: Integer = 100);
|
---|
402 | var
|
---|
403 | I, Count: Integer;
|
---|
404 | PropInfo: PPropInfo;
|
---|
405 | PropList: PPropList;
|
---|
406 | // Name: string;
|
---|
407 | begin
|
---|
408 | LogMessage('Destroy class: ' + Self.ClassName);
|
---|
409 | if Depth >= 0 then begin
|
---|
410 | Store(0);
|
---|
411 | if Self.ClassInfo = nil then raise Exception.Create('Class ' + Self.ClassName + ' doesn''t provide RTTI information!');
|
---|
412 | Count := GetTypeData(Self.ClassInfo)^.PropCount;
|
---|
413 | if Count > 0 then with FDatabase do begin
|
---|
414 | ProcessedClass := Self;
|
---|
415 | GetMem(PropList, Count * SizeOf(Pointer));
|
---|
416 | try
|
---|
417 | GetPropInfos(Self.ClassInfo, PropList);
|
---|
418 | for I := 0 to Count - 1 do
|
---|
419 | begin
|
---|
420 | PropInfo := PropList^[I];
|
---|
421 | if PropInfo = nil then
|
---|
422 | Break;
|
---|
423 | if IsStoredProp(Self, PropInfo) then
|
---|
424 | DestroyProperty(Self, PropInfo, Depth);
|
---|
425 | end;
|
---|
426 | finally
|
---|
427 | FreeMem(PropList, Count * SizeOf(Pointer));
|
---|
428 | end;
|
---|
429 | end;
|
---|
430 | inherited Destroy;
|
---|
431 | end;
|
---|
432 | end;
|
---|
433 |
|
---|
434 | procedure TDbObject.Store(Depth: Integer = 1);
|
---|
435 | var
|
---|
436 | Data: TAssociativeArray;
|
---|
437 | I, Count: Integer;
|
---|
438 | PropInfo: PPropInfo;
|
---|
439 | PropList: PPropList;
|
---|
440 | // Name: string;
|
---|
441 | begin
|
---|
442 | LogMessage('Write class: ' + Self.ClassName);
|
---|
443 | if Depth >= 0 then begin
|
---|
444 | Data := TAssociativeArray.Create;
|
---|
445 | if Self.ClassInfo = nil then raise Exception.Create('Trida '+Self.ClassName+' neposkytuje RTTI informace!');
|
---|
446 | Count := GetTypeData(Self.ClassInfo)^.PropCount;
|
---|
447 | if Count > 0 then with FDatabase do begin
|
---|
448 | GetMem(PropList, Count * SizeOf(Pointer));
|
---|
449 | try
|
---|
450 | GetPropInfos(Self.ClassInfo, PropList);
|
---|
451 | for I := 0 to Count - 1 do
|
---|
452 | begin
|
---|
453 | PropInfo := PropList^[I];
|
---|
454 | if PropInfo = nil then
|
---|
455 | Break;
|
---|
456 | if IsStoredProp(Self, PropInfo) then
|
---|
457 | WriteProperty(Self, PropInfo, Data, Depth);
|
---|
458 | end;
|
---|
459 |
|
---|
460 | ProcessedClass := Self;
|
---|
461 | repeat
|
---|
462 | Replace(Self.ClassName, Data);
|
---|
463 | until not RepeatLastAction;
|
---|
464 | FId := FDatabase.LastInsertId;
|
---|
465 | finally
|
---|
466 | FreeMem(PropList, Count * SizeOf(Pointer));
|
---|
467 | end;
|
---|
468 | end;
|
---|
469 | // Instance.DefineProperties(Self);
|
---|
470 | end;
|
---|
471 | end;
|
---|
472 |
|
---|
473 | function TDbObject.SearchPropertyByPointer(P: Pointer): string;
|
---|
474 | var
|
---|
475 | // Data: TAssocArray;
|
---|
476 | I, Count: Integer;
|
---|
477 | PropInfo: PPropInfo;
|
---|
478 | PropList: PPropList;
|
---|
479 | Instance: TObject;
|
---|
480 | // Name: string;
|
---|
481 | begin
|
---|
482 | Instance := Self;
|
---|
483 | if Self.ClassInfo = nil then raise Exception.Create('Trida '+Self.ClassName+' neposkytuje RTTI informace!');
|
---|
484 | Count := GetTypeData(Self.ClassInfo)^.PropCount;
|
---|
485 | if Count > 0 then with FDatabase do begin
|
---|
486 | ProcessedClass := Self;
|
---|
487 | GetMem(PropList, Count * SizeOf(Pointer));
|
---|
488 | try
|
---|
489 | GetPropInfos(Self.ClassInfo, PropList);
|
---|
490 | for I := 0 to Count - 1 do
|
---|
491 | begin
|
---|
492 | PropInfo := PropList^[I];
|
---|
493 | if PropInfo = nil then
|
---|
494 | Break;
|
---|
495 | if IsStoredProp(Instance, PropInfo) then
|
---|
496 | if GetObjectProp(Self,PropInfo) = P then begin
|
---|
497 | Result := PropInfo.Name;
|
---|
498 | Break;
|
---|
499 | end;
|
---|
500 | end;
|
---|
501 | finally
|
---|
502 | FreeMem(PropList, Count * SizeOf(Pointer));
|
---|
503 | end;
|
---|
504 | end;
|
---|
505 | end;
|
---|
506 |
|
---|
507 | { TDbList }
|
---|
508 |
|
---|
509 | procedure TDbList.CheckId;
|
---|
510 | var
|
---|
511 | Rows: TDbRows;
|
---|
512 | begin
|
---|
513 | if FId = 0 then begin
|
---|
514 | FDatabase.ProcessedClass := Self;
|
---|
515 | Rows := FDatabase.Select(Self.ClassName, 'MAX(ListId)');
|
---|
516 | // ShowMessage(Rows[0].Values['MAX(ListId)']);
|
---|
517 | if Rows.Count > 0 then begin
|
---|
518 | if Rows[0].Values['MAX(ListId)'] = '' then FId := 1 else
|
---|
519 | FId := StrToInt(Rows[0].Values['MAX(ListId)']) + 1;
|
---|
520 | end else FId := 1;
|
---|
521 | Rows.Free;
|
---|
522 | end;
|
---|
523 | end;
|
---|
524 |
|
---|
525 | constructor TDbList.Create(ADatabase: TDatabase; Id: Integer);
|
---|
526 | begin
|
---|
527 | FId := Id;
|
---|
528 | FDatabase := ADatabase;
|
---|
529 | // inherited Create(FDatabase);
|
---|
530 | //Load;
|
---|
531 | end;
|
---|
532 |
|
---|
533 | procedure TDbList.Delete;
|
---|
534 | var
|
---|
535 | I: Integer;
|
---|
536 | begin
|
---|
537 | for I := 0 to Count-1 do Items[I].Delete;
|
---|
538 | FDatabase.Select(Self.ClassName, 'ListId=' + IntToStr(FId))
|
---|
539 | end;
|
---|
540 |
|
---|
541 | destructor TDbList.Destroy(Depth: Integer = 100);
|
---|
542 | var
|
---|
543 | I: Integer;
|
---|
544 | begin
|
---|
545 | LogMessage('Destroy DbList: ' + Self.ClassName);
|
---|
546 | Store(0);
|
---|
547 | if Depth >= 0 then begin
|
---|
548 | if Depth > 0 then for I := 0 to Count-1 do if Assigned(Items[I]) then TDbObject(Items[I]).Destroy(Depth);
|
---|
549 | inherited Destroy;
|
---|
550 | end;
|
---|
551 | end;
|
---|
552 |
|
---|
553 | function TDbList.Get(Index: Integer): TDbObject;
|
---|
554 | begin
|
---|
555 | Result := inherited Get(Index);
|
---|
556 | end;
|
---|
557 |
|
---|
558 | procedure TDbList.Load(Depth: Integer = 1);
|
---|
559 | var
|
---|
560 | // B: TObject;
|
---|
561 | DbRows: TDbRows;
|
---|
562 | I: Integer;
|
---|
563 | // d: TPersistentList;
|
---|
564 | begin
|
---|
565 | // d:= TPersistentList.Create;
|
---|
566 | // ShowMessage(IntToStr(Integer(d.ClassInfo)));
|
---|
567 | FDatabase.ProcessedClass := Self;
|
---|
568 | //ShowMessage(IntToStr(Integer(FDatabase.ProcessedClass.ClassInfo)));
|
---|
569 | FDatabase.Table := Self.ClassName;
|
---|
570 | DbRows := FDatabase.Select(FDatabase.Table, '*', 'ListId=' + IntToStr(FId) + ' ORDER BY id');
|
---|
571 | Count := DbRows.Count;
|
---|
572 | for I := 0 to DbRows.Count-1 do begin
|
---|
573 | Items[I] := ItemsClass.Create(FDatabase);
|
---|
574 | if Depth > 0 then Items[I].LoadById(StrToInt(DbRows.Data[I].Values['ItemId']), Depth-1);
|
---|
575 | // FromRow(Items[I], DbRows.Data[I]);
|
---|
576 | end;
|
---|
577 | end;
|
---|
578 |
|
---|
579 | procedure TDbList.Put(Index: Integer; const Value: TDbObject);
|
---|
580 | begin
|
---|
581 | inherited Put(Index, Value);
|
---|
582 | end;
|
---|
583 |
|
---|
584 | procedure TDbList.Store(Depth: Integer = 1);
|
---|
585 | var
|
---|
586 | I: Integer;
|
---|
587 | Data: TAssociativeArray;
|
---|
588 | begin
|
---|
589 | if Depth >= 0 then begin
|
---|
590 | CheckId;
|
---|
591 | FDatabase.ProcessedClass := Self;
|
---|
592 | FDatabase.Delete(Self.ClassName, 'ListId='+IntToStr(FId));
|
---|
593 | if Self.ClassName = 'tmeasurepointsetlist' then LogMessage('d');
|
---|
594 | Data := TAssociativeArray.Create;
|
---|
595 | Data.AddKeyValue('ListId', IntToStr(FId));
|
---|
596 | Data.AddKeyValue('ItemId', '0');
|
---|
597 | for I := 0 to Count-1 do
|
---|
598 | if Assigned(Items[I]) then begin
|
---|
599 | if Depth > 0 then Items[I].Store(Depth);
|
---|
600 | Data.Values['ItemId'] := IntToStr(TDbObject(Items[I]).FId);
|
---|
601 | FDatabase.ProcessedClass := Self;
|
---|
602 | FDatabase.Insert(Self.ClassName, Data);
|
---|
603 | end else raise Exception.Create('Item '+IntToStr(I)+' in '+Self.ClassName+' is nil!');
|
---|
604 | Data.Free;
|
---|
605 | // inherited StoreClassName(FItemsClass.ClassName+'_list', Depth);
|
---|
606 | end;
|
---|
607 | end;
|
---|
608 |
|
---|
609 | { TDatabase }
|
---|
610 |
|
---|
611 | procedure TDatabase.CheckTable;
|
---|
612 | begin
|
---|
613 |
|
---|
614 | end;
|
---|
615 |
|
---|
616 | constructor TDatabase.Create;
|
---|
617 | begin
|
---|
618 | inherited;
|
---|
619 | end;
|
---|
620 |
|
---|
621 | destructor TDatabase.Destroy;
|
---|
622 | begin
|
---|
623 | Disconnect;
|
---|
624 | inherited;
|
---|
625 | end;
|
---|
626 |
|
---|
627 | procedure TDbObject.LoadFromRow(Row: TAssociativeArray; Depth: Integer = 1);
|
---|
628 | var
|
---|
629 | I, Count: Integer;
|
---|
630 | PropInfo: PPropInfo;
|
---|
631 | PropList: PPropList;
|
---|
632 | begin
|
---|
633 | LogMessage('Load class: ' + Self.ClassName);
|
---|
634 | // ShowMessage(Row.GetAllValues);
|
---|
635 | FRow := Row;
|
---|
636 | if Self.ClassInfo = nil then raise Exception.Create('Trida '+Self.ClassName+' neposkytuje RTTI informace!');
|
---|
637 | Count := GetTypeData(Self.ClassInfo)^.PropCount;
|
---|
638 | if Count > 0 then with FDatabase do begin
|
---|
639 | ProcessedClass := Self;
|
---|
640 | GetMem(PropList, Count * SizeOf(Pointer));
|
---|
641 | try
|
---|
642 | GetPropInfos(Self.ClassInfo, PropList);
|
---|
643 | for I := 0 to Count - 1 do
|
---|
644 | begin
|
---|
645 | PropInfo := PropList^[I];
|
---|
646 | if PropInfo = nil then
|
---|
647 | Break;
|
---|
648 | if IsStoredProp(Self, PropInfo) then
|
---|
649 | ReadProperty(Self, PropInfo, Row, Depth);
|
---|
650 | end;
|
---|
651 | finally
|
---|
652 | FreeMem(PropList, Count * SizeOf(Pointer));
|
---|
653 | end;
|
---|
654 | end;
|
---|
655 | // Instance.DefineProperties(Self);
|
---|
656 | // Data.Free;
|
---|
657 | FRow := nil;
|
---|
658 | end;
|
---|
659 |
|
---|
660 | procedure TDatabase.HandleError(Sender: TObject);
|
---|
661 | var
|
---|
662 | Name: string;
|
---|
663 | PropInfo: PPropInfo;
|
---|
664 | begin
|
---|
665 | if LastErrorNumber = 1146 then begin // Table doesn't exist
|
---|
666 | CreateTable(Table);
|
---|
667 | RepeatLastAction := True;
|
---|
668 | end else
|
---|
669 | if LastErrorNumber = 1054 then begin // Unknown column
|
---|
670 | Name := Copy(LastErrorMessage, Pos('''', LastErrorMessage) + 1, Length(LastErrorMessage));
|
---|
671 | Name := Copy(Name, 1, Pos('''', Name)-1);
|
---|
672 | //ShowMessage(IntToStr(Integer(ProcessedClass.ClassInfo)));
|
---|
673 | //ShowMessage(ProcessedClass.ClassName);
|
---|
674 | PropInfo := GetPropInfo(ProcessedClass.ClassInfo, Name);
|
---|
675 | if PropInfo = nil then
|
---|
676 | raise Exception.Create('Missing published property '+Name+' in class '+ProcessedClass.ClassName)
|
---|
677 | else CreateColumn(Table, PropInfo.Name, PropInfo.PropType^.Kind);
|
---|
678 | RepeatLastAction := True;
|
---|
679 | end else begin
|
---|
680 | if Assigned(FOnError) then FOnError(Self);
|
---|
681 | end;
|
---|
682 | end;
|
---|
683 |
|
---|
684 | constructor TDbObject.Create(ADatabase: TDatabase);
|
---|
685 | begin
|
---|
686 | FDatabase := ADatabase;
|
---|
687 | FId := 0;
|
---|
688 | end;
|
---|
689 |
|
---|
690 | procedure TDbObject.LoadById(Id: Integer; Depth: Integer = 1);
|
---|
691 | var
|
---|
692 | Rows: TDbRows;
|
---|
693 | begin
|
---|
694 | FId := Id;
|
---|
695 | Rows := FDatabase.Select(Self.ClassName, '*', 'id=' + IntToStr(FId));
|
---|
696 | if Rows.Count > 0 then LoadFromRow(Rows[0], Depth) else begin
|
---|
697 | Store;
|
---|
698 | Rows.Free;
|
---|
699 | Rows := FDatabase.Select(Self.ClassName, '*', 'id=' + IntToStr(FId));
|
---|
700 | LoadFromRow(Rows[0], Depth);
|
---|
701 | end;
|
---|
702 | Rows.Free;
|
---|
703 | end;
|
---|
704 |
|
---|
705 | { TPersistentList }
|
---|
706 |
|
---|
707 | destructor TPersistentList.Destroy;
|
---|
708 | begin
|
---|
709 | Clear;
|
---|
710 | end;
|
---|
711 |
|
---|
712 | function TPersistentList.Add(Item: Pointer): Integer;
|
---|
713 | begin
|
---|
714 | Result := FCount;
|
---|
715 | if Result = FCapacity then
|
---|
716 | Grow;
|
---|
717 | FList^[Result] := Item;
|
---|
718 | Inc(FCount);
|
---|
719 | if Item <> nil then
|
---|
720 | Notify(Item, lnAdded);
|
---|
721 | end;
|
---|
722 |
|
---|
723 | procedure TPersistentList.Clear;
|
---|
724 | begin
|
---|
725 | SetCount(0);
|
---|
726 | SetCapacity(0);
|
---|
727 | end;
|
---|
728 |
|
---|
729 | procedure TPersistentList.Delete(Index: Integer);
|
---|
730 | var
|
---|
731 | Temp: Pointer;
|
---|
732 | begin
|
---|
733 | if (Index < 0) or (Index >= FCount) then
|
---|
734 | Error(@SListIndexError, Index);
|
---|
735 | Temp := Items[Index];
|
---|
736 | Dec(FCount);
|
---|
737 | if Index < FCount then
|
---|
738 | System.Move(FList^[Index + 1], FList^[Index],
|
---|
739 | (FCount - Index) * SizeOf(Pointer));
|
---|
740 | if Temp <> nil then
|
---|
741 | Notify(Temp, lnDeleted);
|
---|
742 | end;
|
---|
743 |
|
---|
744 | class procedure TPersistentList.Error(const Msg: string; Data: Integer);
|
---|
745 |
|
---|
746 | (*
|
---|
747 | function ReturnAddr: Pointer;
|
---|
748 | asm
|
---|
749 | MOV EAX,[EBP+4]
|
---|
750 | end;
|
---|
751 | *)
|
---|
752 |
|
---|
753 | begin
|
---|
754 | // raise EListError.CreateFmt(Msg, [Data]) at ReturnAddr;
|
---|
755 | end;
|
---|
756 |
|
---|
757 | class procedure TPersistentList.Error(Msg: PResStringRec; Data: Integer);
|
---|
758 | begin
|
---|
759 | TPersistentList.Error(LoadResString(Msg), Data);
|
---|
760 | end;
|
---|
761 |
|
---|
762 | procedure TPersistentList.Exchange(Index1, Index2: Integer);
|
---|
763 | var
|
---|
764 | Item: Pointer;
|
---|
765 | begin
|
---|
766 | if (Index1 < 0) or (Index1 >= FCount) then
|
---|
767 | Error(@SListIndexError, Index1);
|
---|
768 | if (Index2 < 0) or (Index2 >= FCount) then
|
---|
769 | Error(@SListIndexError, Index2);
|
---|
770 | Item := FList^[Index1];
|
---|
771 | FList^[Index1] := FList^[Index2];
|
---|
772 | FList^[Index2] := Item;
|
---|
773 | end;
|
---|
774 |
|
---|
775 | function TPersistentList.Expand: TPersistentList;
|
---|
776 | begin
|
---|
777 | if FCount = FCapacity then
|
---|
778 | Grow;
|
---|
779 | Result := Self;
|
---|
780 | end;
|
---|
781 |
|
---|
782 | function TPersistentList.First: Pointer;
|
---|
783 | begin
|
---|
784 | Result := Get(0);
|
---|
785 | end;
|
---|
786 |
|
---|
787 | function TPersistentList.Get(Index: Integer): Pointer;
|
---|
788 | begin
|
---|
789 | if (Index < 0) or (Index >= FCount) then
|
---|
790 | Error(@SListIndexError, Index);
|
---|
791 | Result := FList^[Index];
|
---|
792 | end;
|
---|
793 |
|
---|
794 | procedure TPersistentList.Grow;
|
---|
795 | var
|
---|
796 | Delta: Integer;
|
---|
797 | begin
|
---|
798 | if FCapacity > 64 then
|
---|
799 | Delta := FCapacity div 4
|
---|
800 | else
|
---|
801 | if FCapacity > 8 then
|
---|
802 | Delta := 16
|
---|
803 | else
|
---|
804 | Delta := 4;
|
---|
805 | SetCapacity(FCapacity + Delta);
|
---|
806 | end;
|
---|
807 |
|
---|
808 | function TPersistentList.IndexOf(Item: Pointer): Integer;
|
---|
809 | begin
|
---|
810 | Result := 0;
|
---|
811 | while (Result < FCount) and (FList^[Result] <> Item) do
|
---|
812 | Inc(Result);
|
---|
813 | if Result = FCount then
|
---|
814 | Result := -1;
|
---|
815 | end;
|
---|
816 |
|
---|
817 | procedure TPersistentList.Insert(Index: Integer; Item: Pointer);
|
---|
818 | begin
|
---|
819 | if (Index < 0) or (Index > FCount) then
|
---|
820 | Error(@SListIndexError, Index);
|
---|
821 | if FCount = FCapacity then
|
---|
822 | Grow;
|
---|
823 | if Index < FCount then
|
---|
824 | System.Move(FList^[Index], FList^[Index + 1],
|
---|
825 | (FCount - Index) * SizeOf(Pointer));
|
---|
826 | FList^[Index] := Item;
|
---|
827 | Inc(FCount);
|
---|
828 | if Item <> nil then
|
---|
829 | Notify(Item, lnAdded);
|
---|
830 | end;
|
---|
831 |
|
---|
832 | function TPersistentList.Last: Pointer;
|
---|
833 | begin
|
---|
834 | Result := Get(FCount - 1);
|
---|
835 | end;
|
---|
836 |
|
---|
837 | procedure TPersistentList.Move(CurIndex, NewIndex: Integer);
|
---|
838 | var
|
---|
839 | Item: Pointer;
|
---|
840 | begin
|
---|
841 | if CurIndex <> NewIndex then
|
---|
842 | begin
|
---|
843 | if (NewIndex < 0) or (NewIndex >= FCount) then
|
---|
844 | Error(@SListIndexError, NewIndex);
|
---|
845 | Item := Get(CurIndex);
|
---|
846 | FList^[CurIndex] := nil;
|
---|
847 | Delete(CurIndex);
|
---|
848 | Insert(NewIndex, nil);
|
---|
849 | FList^[NewIndex] := Item;
|
---|
850 | end;
|
---|
851 | end;
|
---|
852 |
|
---|
853 | procedure TPersistentList.Put(Index: Integer; Item: Pointer);
|
---|
854 | var
|
---|
855 | Temp: Pointer;
|
---|
856 | begin
|
---|
857 | if (Index < 0) or (Index >= FCount) then
|
---|
858 | Error(@SListIndexError, Index);
|
---|
859 | if Item <> FList^[Index] then
|
---|
860 | begin
|
---|
861 | Temp := FList^[Index];
|
---|
862 | FList^[Index] := Item;
|
---|
863 | if Temp <> nil then
|
---|
864 | Notify(Temp, lnDeleted);
|
---|
865 | if Item <> nil then
|
---|
866 | Notify(Item, lnAdded);
|
---|
867 | end;
|
---|
868 | end;
|
---|
869 |
|
---|
870 | function TPersistentList.Remove(Item: Pointer): Integer;
|
---|
871 | begin
|
---|
872 | Result := IndexOf(Item);
|
---|
873 | if Result >= 0 then
|
---|
874 | Delete(Result);
|
---|
875 | end;
|
---|
876 |
|
---|
877 | procedure TPersistentList.Pack;
|
---|
878 | var
|
---|
879 | I: Integer;
|
---|
880 | begin
|
---|
881 | for I := FCount - 1 downto 0 do
|
---|
882 | if Items[I] = nil then
|
---|
883 | Delete(I);
|
---|
884 | end;
|
---|
885 |
|
---|
886 | procedure TPersistentList.SetCapacity(NewCapacity: Integer);
|
---|
887 | begin
|
---|
888 | if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
|
---|
889 | Error(@SListCapacityError, NewCapacity);
|
---|
890 | if NewCapacity <> FCapacity then
|
---|
891 | begin
|
---|
892 | ReallocMem(FList, NewCapacity * SizeOf(Pointer));
|
---|
893 | FCapacity := NewCapacity;
|
---|
894 | end;
|
---|
895 | end;
|
---|
896 |
|
---|
897 | procedure TPersistentList.SetCount(NewCount: Integer);
|
---|
898 | var
|
---|
899 | I: Integer;
|
---|
900 | begin
|
---|
901 | if (NewCount < 0) or (NewCount > MaxListSize) then
|
---|
902 | Error(@SListCountError, NewCount);
|
---|
903 | if NewCount > FCapacity then
|
---|
904 | SetCapacity(NewCount);
|
---|
905 | if NewCount > FCount then
|
---|
906 | FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), 0)
|
---|
907 | else
|
---|
908 | for I := FCount - 1 downto NewCount do
|
---|
909 | Delete(I);
|
---|
910 | FCount := NewCount;
|
---|
911 | end;
|
---|
912 |
|
---|
913 | procedure QuickSort(SortList: PPointerList; L, R: Integer;
|
---|
914 | SCompare: TListSortCompare);
|
---|
915 | var
|
---|
916 | I, J: Integer;
|
---|
917 | P, T: Pointer;
|
---|
918 | begin
|
---|
919 | repeat
|
---|
920 | I := L;
|
---|
921 | J := R;
|
---|
922 | P := SortList^[(L + R) shr 1];
|
---|
923 | repeat
|
---|
924 | while SCompare(SortList^[I], P) < 0 do
|
---|
925 | Inc(I);
|
---|
926 | while SCompare(SortList^[J], P) > 0 do
|
---|
927 | Dec(J);
|
---|
928 | if I <= J then
|
---|
929 | begin
|
---|
930 | T := SortList^[I];
|
---|
931 | SortList^[I] := SortList^[J];
|
---|
932 | SortList^[J] := T;
|
---|
933 | Inc(I);
|
---|
934 | Dec(J);
|
---|
935 | end;
|
---|
936 | until I > J;
|
---|
937 | if L < J then
|
---|
938 | QuickSort(SortList, L, J, SCompare);
|
---|
939 | L := I;
|
---|
940 | until I >= R;
|
---|
941 | end;
|
---|
942 |
|
---|
943 | procedure TPersistentList.Sort(Compare: TListSortCompare);
|
---|
944 | begin
|
---|
945 | if (FList <> nil) and (Count > 0) then
|
---|
946 | QuickSort(FList, 0, Count - 1, Compare);
|
---|
947 | end;
|
---|
948 |
|
---|
949 | function TPersistentList.Extract(Item: Pointer): Pointer;
|
---|
950 | var
|
---|
951 | I: Integer;
|
---|
952 | begin
|
---|
953 | Result := nil;
|
---|
954 | I := IndexOf(Item);
|
---|
955 | if I >= 0 then
|
---|
956 | begin
|
---|
957 | Result := Item;
|
---|
958 | FList^[I] := nil;
|
---|
959 | Delete(I);
|
---|
960 | Notify(Result, lnExtracted);
|
---|
961 | end;
|
---|
962 | end;
|
---|
963 |
|
---|
964 | procedure TPersistentList.Notify(Ptr: Pointer; Action: TListNotification);
|
---|
965 | begin
|
---|
966 | end;
|
---|
967 |
|
---|
968 | procedure TPersistentList.Assign(ListA: TPersistentList; AOperator: TListAssignOp; ListB: TPersistentList);
|
---|
969 | var
|
---|
970 | I: Integer;
|
---|
971 | LTemp, LSource: TPersistentList;
|
---|
972 | begin
|
---|
973 | // ListB given?
|
---|
974 | if ListB <> nil then
|
---|
975 | begin
|
---|
976 | LSource := ListB;
|
---|
977 | Assign(ListA);
|
---|
978 | end
|
---|
979 | else
|
---|
980 | LSource := ListA;
|
---|
981 |
|
---|
982 | // on with the show
|
---|
983 | case AOperator of
|
---|
984 |
|
---|
985 | // 12345, 346 = 346 : only those in the new list
|
---|
986 | laCopy:
|
---|
987 | begin
|
---|
988 | Clear;
|
---|
989 | Capacity := LSource.Capacity;
|
---|
990 | for I := 0 to LSource.Count - 1 do
|
---|
991 | Add(LSource[I]);
|
---|
992 | end;
|
---|
993 |
|
---|
994 | // 12345, 346 = 34 : intersection of the two lists
|
---|
995 | laAnd:
|
---|
996 | for I := Count - 1 downto 0 do
|
---|
997 | if LSource.IndexOf(Items[I]) = -1 then
|
---|
998 | Delete(I);
|
---|
999 |
|
---|
1000 | // 12345, 346 = 123456 : union of the two lists
|
---|
1001 | laOr:
|
---|
1002 | for I := 0 to LSource.Count - 1 do
|
---|
1003 | if IndexOf(LSource[I]) = -1 then
|
---|
1004 | Add(LSource[I]);
|
---|
1005 |
|
---|
1006 | // 12345, 346 = 1256 : only those not in both lists
|
---|
1007 | laXor:
|
---|
1008 | begin
|
---|
1009 | LTemp := TPersistentList.Create; // Temp holder of 4 byte values
|
---|
1010 | try
|
---|
1011 | LTemp.Capacity := LSource.Count;
|
---|
1012 | for I := 0 to LSource.Count - 1 do
|
---|
1013 | if IndexOf(LSource[I]) = -1 then
|
---|
1014 | LTemp.Add(LSource[I]);
|
---|
1015 | for I := Count - 1 downto 0 do
|
---|
1016 | if LSource.IndexOf(Items[I]) <> -1 then
|
---|
1017 | Delete(I);
|
---|
1018 | I := Count + LTemp.Count;
|
---|
1019 | if Capacity < I then
|
---|
1020 | Capacity := I;
|
---|
1021 | for I := 0 to LTemp.Count - 1 do
|
---|
1022 | Add(LTemp[I]);
|
---|
1023 | finally
|
---|
1024 | LTemp.Free;
|
---|
1025 | end;
|
---|
1026 | end;
|
---|
1027 |
|
---|
1028 | // 12345, 346 = 125 : only those unique to source
|
---|
1029 | laSrcUnique:
|
---|
1030 | for I := Count - 1 downto 0 do
|
---|
1031 | if LSource.IndexOf(Items[I]) <> -1 then
|
---|
1032 | Delete(I);
|
---|
1033 |
|
---|
1034 | // 12345, 346 = 6 : only those unique to dest
|
---|
1035 | laDestUnique:
|
---|
1036 | begin
|
---|
1037 | LTemp := TPersistentList.Create;
|
---|
1038 | try
|
---|
1039 | LTemp.Capacity := LSource.Count;
|
---|
1040 | for I := LSource.Count - 1 downto 0 do
|
---|
1041 | if IndexOf(LSource[I]) = -1 then
|
---|
1042 | LTemp.Add(LSource[I]);
|
---|
1043 | Assign(LTemp);
|
---|
1044 | finally
|
---|
1045 | LTemp.Free;
|
---|
1046 | end;
|
---|
1047 | end;
|
---|
1048 | end;
|
---|
1049 | end;
|
---|
1050 |
|
---|
1051 | procedure TDbObject.DeleteProperty(Instance: TDbObject; PropInfo: PPropInfo);
|
---|
1052 | var
|
---|
1053 | PropType: PTypeInfo;
|
---|
1054 |
|
---|
1055 | procedure WriteObjectProp;
|
---|
1056 | var
|
---|
1057 | Value: TObject;
|
---|
1058 | // OldAncestor: TPersistent;
|
---|
1059 | // SavePropPath, ComponentValue: string;
|
---|
1060 | Setter: Longint;
|
---|
1061 | TargetObject: ^TObject;
|
---|
1062 | begin
|
---|
1063 | Value := TObject(GetOrdProp(Instance, PropInfo));
|
---|
1064 | if Value = nil then begin
|
---|
1065 | end else begin
|
---|
1066 | if Value is TDbObject then begin
|
---|
1067 | TDbObject(Value).Delete;
|
---|
1068 | end else if Value is TDbList then begin
|
---|
1069 | TDbList(Value).Delete;
|
---|
1070 | end;
|
---|
1071 |
|
---|
1072 | // Set object reference to nil
|
---|
1073 | Setter := Longint(PropInfo^.SetProc);
|
---|
1074 | if (Setter and $FF000000) = $FF000000 then
|
---|
1075 | begin // field - Setter is the field's offset in the instance data
|
---|
1076 | TargetObject := Pointer(Integer(Instance) + (Setter and $00FFFFFF));
|
---|
1077 | TargetObject^ := nil; // auto ref count
|
---|
1078 | end;
|
---|
1079 | end;
|
---|
1080 | end;
|
---|
1081 |
|
---|
1082 |
|
---|
1083 | begin
|
---|
1084 | // Using IsDefaultPropertyValue will tell us if we should write out
|
---|
1085 | // a given property because it was different from the default or
|
---|
1086 | // different from the Ancestor (if applicable).
|
---|
1087 | if (PropInfo^.GetProc <> nil) and
|
---|
1088 | ((PropInfo^.SetProc <> nil) or
|
---|
1089 | ((PropInfo^.PropType^.Kind = tkClass) and
|
---|
1090 | (TObject(GetOrdProp(Instance, PropInfo)) is TComponent) and
|
---|
1091 | (csSubComponent in TComponent(GetOrdProp(Instance, PropInfo)).ComponentStyle))) then
|
---|
1092 | begin
|
---|
1093 | LogMessage('Destroy property: '+Instance.ClassName+'.'+PropInfo.Name);
|
---|
1094 | //if not IsDefaultPropertyValue(Instance, PropInfo, GetLookupInfo) then
|
---|
1095 | begin
|
---|
1096 | //AncestorValid := AncestorIsValid(Ancestor, Root, RootAncestor);
|
---|
1097 | PropType := PropInfo^.PropType;
|
---|
1098 | case PropType^.Kind of
|
---|
1099 | tkClass:
|
---|
1100 | WriteObjectProp;
|
---|
1101 | end;
|
---|
1102 | end;
|
---|
1103 | end;
|
---|
1104 | end;
|
---|
1105 |
|
---|
1106 | procedure TDbObject.DestroyProperty(Instance: TDbObject; PropInfo: PPropInfo; Depth: Integer);
|
---|
1107 | var
|
---|
1108 | PropType: PTypeInfo;
|
---|
1109 |
|
---|
1110 | procedure WriteObjectProp;
|
---|
1111 | var
|
---|
1112 | Value: TObject;
|
---|
1113 | // OldAncestor: TPersistent;
|
---|
1114 | // SavePropPath, ComponentValue: string;
|
---|
1115 | Setter: Longint;
|
---|
1116 | TargetObject: ^TObject;
|
---|
1117 | begin
|
---|
1118 | Value := TObject(GetOrdProp(Instance, PropInfo));
|
---|
1119 | if Value = nil then begin
|
---|
1120 | end else begin
|
---|
1121 | if Value is TDbObject then begin
|
---|
1122 | TDbObject(Value).Destroy(Depth - 1);
|
---|
1123 | end else if Value is TDbList then begin
|
---|
1124 | TDbList(Value).Destroy(Depth - 1);
|
---|
1125 | end;
|
---|
1126 |
|
---|
1127 | // Set object reference to nil
|
---|
1128 | Setter := Longint(PropInfo^.SetProc);
|
---|
1129 | if (Setter and $FF000000) = $FF000000 then
|
---|
1130 | begin // field - Setter is the field's offset in the instance data
|
---|
1131 | TargetObject := Pointer(Integer(Instance) + (Setter and $00FFFFFF));
|
---|
1132 | TargetObject^ := nil; // auto ref count
|
---|
1133 | end;
|
---|
1134 | end;
|
---|
1135 | end;
|
---|
1136 |
|
---|
1137 |
|
---|
1138 | begin
|
---|
1139 | // Using IsDefaultPropertyValue will tell us if we should write out
|
---|
1140 | // a given property because it was different from the default or
|
---|
1141 | // different from the Ancestor (if applicable).
|
---|
1142 | if (PropInfo^.GetProc <> nil) and
|
---|
1143 | ((PropInfo^.SetProc <> nil) or
|
---|
1144 | ((PropInfo^.PropType^.Kind = tkClass) and
|
---|
1145 | (TObject(GetOrdProp(Instance, PropInfo)) is TComponent) and
|
---|
1146 | (csSubComponent in TComponent(GetOrdProp(Instance, PropInfo)).ComponentStyle))) then
|
---|
1147 | begin
|
---|
1148 | LogMessage('Destroy property: '+Instance.ClassName+'.'+PropInfo.Name);
|
---|
1149 | //if not IsDefaultPropertyValue(Instance, PropInfo, GetLookupInfo) then
|
---|
1150 | begin
|
---|
1151 | //AncestorValid := AncestorIsValid(Ancestor, Root, RootAncestor);
|
---|
1152 | PropType := PropInfo^.PropType;
|
---|
1153 | case PropType^.Kind of
|
---|
1154 | tkClass:
|
---|
1155 | WriteObjectProp;
|
---|
1156 | end;
|
---|
1157 | end;
|
---|
1158 | end;
|
---|
1159 | end;
|
---|
1160 |
|
---|
1161 | procedure TDbObject.Load(Depth: Integer);
|
---|
1162 | begin
|
---|
1163 | LoadById(Id, Depth);
|
---|
1164 | end;
|
---|
1165 |
|
---|
1166 | procedure TDbObject.Delete;
|
---|
1167 | var
|
---|
1168 | I, Count: Integer;
|
---|
1169 | PropInfo: PPropInfo;
|
---|
1170 | PropList: PPropList;
|
---|
1171 | // Name: string;
|
---|
1172 | begin
|
---|
1173 | LogMessage('Delete class: '+Self.ClassName);
|
---|
1174 | if Self.ClassInfo = nil then raise Exception.Create('Class '+Self.ClassName+' doesn''t provide RTTI information!');
|
---|
1175 | Count := GetTypeData(Self.ClassInfo)^.PropCount;
|
---|
1176 | if Count > 0 then with FDatabase do begin
|
---|
1177 | ProcessedClass := Self;
|
---|
1178 | GetMem(PropList, Count * SizeOf(Pointer));
|
---|
1179 | try
|
---|
1180 | GetPropInfos(Self.ClassInfo, PropList);
|
---|
1181 | for I := 0 to Count - 1 do
|
---|
1182 | begin
|
---|
1183 | PropInfo := PropList^[I];
|
---|
1184 | if PropInfo = nil then
|
---|
1185 | Break;
|
---|
1186 | if IsStoredProp(Self, PropInfo) then
|
---|
1187 | DeleteProperty(Self, PropInfo);
|
---|
1188 | end;
|
---|
1189 | finally
|
---|
1190 | FreeMem(PropList, Count * SizeOf(Pointer));
|
---|
1191 | end;
|
---|
1192 | end;
|
---|
1193 | Database.Delete(Self.ClassName, 'id=' + IntToStr(Id));
|
---|
1194 | inherited Destroy;
|
---|
1195 | end;
|
---|
1196 |
|
---|
1197 | end.
|
---|