source: trunk/UDatabase.pas

Last change on this file was 29, checked in by chronos, 20 months ago
  • Fixed: Load table fields in records list and record edit form.
  • Fixed: Record add needs to insert new row into database.
File size: 20.2 KB
Line 
1unit UDatabase;
2
3interface
4
5uses
6 Classes, SysUtils, ExtCtrls, Dialogs, USqlDatabase, URegistry, UGenerics,
7 Generics.Collections;
8
9type
10 TTable = class;
11 TDbClientType = class;
12 TDbClient = class;
13 TDataType = class;
14 TDbManager = class;
15
16 TFieldType = (ftString, ftInteger, ftDateTime, ftBoolean, ftFloat, ftImage,
17 ftDate, ftTime, ftMapPosition, ftReference);
18
19 { TValue }
20
21 TValue = class
22 procedure Assign(Source: TValue); virtual;
23 function GetString: string; virtual;
24 procedure SetString(Value: string); virtual;
25 function GetStringSQL: string; virtual;
26 procedure SetStringSQL(Value: string); virtual;
27 end;
28
29 TValueClass = class of TValue;
30
31 { TValues }
32
33 TValues = class(TObjectList<TValue>)
34 procedure Assign(Source: TValues);
35 end;
36
37 { TFieldTypeSpecific }
38
39 TFieldTypeSpecific = class
40 procedure Assign(Source: TFieldTypeSpecific); virtual;
41 function GetValueClass: TValueClass; virtual;
42 end;
43
44 TFieldTypeSpecificClass = class of TFieldTypeSpecific;
45
46 { TField }
47
48 TField = class
49 private
50 FDataType: TDataType;
51 procedure SetDataType(AValue: TDataType);
52 public
53 Name: string;
54 TypeRelated: TFieldTypeSpecific;
55 Required: Boolean;
56 ReadOnly: Boolean;
57 TextBefore: string;
58 TextAfter: string;
59 Description: string;
60 AllowNull: string;
61 Pos: TPoint;
62 Size: TPoint;
63 Table: TTable;
64 procedure Assign(Source: TField);
65 function GetValueClass: TValueClass;
66 property DataType: TDataType read FDataType write SetDataType;
67 constructor Create;
68 destructor Destroy; override;
69 end;
70
71 { TFields }
72
73 TFields = class(TObjectList<TField>)
74 Table: TTable;
75 function SearchByName(Name: string): TField;
76 procedure Assign(Source: TFields);
77 function AddNew(Name: string; DataType: TDataType): TField;
78 procedure Load;
79 end;
80
81 { TRecord }
82
83 TRecord = class
84 Table: TTable;
85 Values: TValues;
86 function Match(AValues: TStrings): Boolean;
87 procedure InitValues;
88 procedure Assign(Source: TRecord);
89 constructor Create;
90 destructor Destroy; override;
91 end;
92
93 { TRecords }
94
95 TRecords = class(TObjectList<TRecord>)
96 Table: TTable;
97 procedure Assign(Source: TRecords);
98 function SearchByValue(Name, Value: string): TRecord;
99 function SearchByValues(Values: TStrings): TRecord;
100 function AddNew: TRecord;
101 procedure Load;
102 end;
103
104 { TTable }
105
106 TTable = class
107 Id: Integer;
108 Name: string;
109 Caption: string;
110 Records: TRecords;
111 Fields: TFields;
112 DbClient: TDbClient;
113 RecordsCount: Integer;
114 procedure LoadRecordsCount;
115 procedure Assign(Source: TTable);
116 constructor Create;
117 destructor Destroy; override;
118 end;
119
120 { TTables }
121
122 TTables = class(TObjectList<TTable>)
123 DbClient: TDbClient;
124 function SearchByName(Name: string): TTable;
125 function AddNew(Name: string): TTable;
126 end;
127
128 { TDbConnectParams }
129
130 TDbConnectParams = class
131 protected
132 FConnectionString: string;
133 function GetConnectionString: string; virtual;
134 procedure SetConnectionString(AValue: string); virtual;
135 public
136 property ConnectionString: string read GetConnectionString
137 write SetConnectionString;
138 end;
139
140 TDbConnectParamsClass = class of TDbConnectParams;
141
142 { TDbConnectProfile }
143
144 TDbConnectProfile = class
145 private
146 FClientType: TDbClientType;
147 procedure SetClientType(AValue: TDbClientType);
148 public
149 Name: string;
150 Params: TDbConnectParams;
151 DbManager: TDbManager;
152 destructor Destroy; override;
153 function GetClient: TDbClient;
154 property ClientType: TDbClientType read FClientType write SetClientType;
155 end;
156
157 { TDbConnectProfiles }
158
159 TDbConnectProfiles = class(TObjectList<TDbConnectProfile>)
160 DbManager: TDbManager;
161 procedure LoadFromRegistry(Context: TRegistryContext);
162 procedure SaveToRegistry(Context: TRegistryContext);
163 function SearchByName(Name: string): TDbConnectProfile;
164 end;
165
166 { TDataType }
167
168 TDataType = class
169 Id: Integer;
170 Name: string;
171 Title: string;
172 FieldType: TFieldType;
173 FieldTypeClass: TFieldTypeSpecificClass;
174 end;
175
176 { TDataTypes }
177
178 TDataTypes = class(TObjectList<TDataType>)
179 function RegisterType(Id: Integer; Name, Title: string;
180 FieldType: TFieldType; FieldTypeClass: TFieldTypeSpecificClass): TDataType;
181 function SearchByType(FieldType: TFieldType): TDataType;
182 function SearchByName(Name: string): TDataType;
183 end;
184
185 TDbRows = USqlDatabase.TDbRows;
186
187 { TDbClient }
188
189 TDbClient = class
190 private
191 function GetClientType: TDbClientType;
192 protected
193 FConnectProfile: TDbConnectProfile;
194 procedure SetConnectProfile(AValue: TDbConnectProfile); virtual;
195 public
196 DbManager: TDbManager;
197 procedure Query(Text: string; DbRows: TDbRows = nil); virtual;
198 constructor Create; virtual;
199 procedure Load; virtual;
200 procedure Save; virtual;
201 property ClientType: TDbClientType read GetClientType;
202 property ConnectProfile: TDbConnectProfile read FConnectProfile
203 write SetConnectProfile;
204 end;
205
206 TDbClientClass = class of TDbClient;
207
208 TFieldTypeSet = set of TFieldType;
209
210 { TDbClientType }
211
212 TDbClientType = class
213 Name: string;
214 DataTypes: TDataTypes;
215 DatabaseClientClass: TDbClientClass;
216 ConnectParmasClass: TDbConnectParamsClass;
217 procedure UseTypes(ADataTypes: TDataTypes; Types: TFieldTypeSet);
218 constructor Create;
219 destructor Destroy; override;
220 end;
221
222 { TDbClientTypes }
223
224 TDbClientTypes = class(TObjectList<TDbClientType>)
225 function RegisterClientType(Name: string; DatabaseClass: TDbClientClass;
226 ConnectParamsClass: TDbConnectParamsClass): TDbClientType;
227 function FindByName(Name: string): TDbClientType;
228 end;
229
230 TPreferences = class
231 RememberDatabase: Boolean;
232 LastDatabaseName: string;
233 end;
234
235 { TDbManager }
236
237 TDbManager = class
238 private
239 procedure InitClientTypes;
240 procedure InitDataTypes;
241 public
242 ConnectProfiles: TDbConnectProfiles;
243 ClientTypes: TDbClientTypes;
244 DataTypes: TDataTypes;
245 constructor Create;
246 destructor Destroy; override;
247 end;
248
249resourcestring
250 STypeString = 'String';
251 STypeInteger = 'Integer';
252 STypeFloat = 'Float';
253 STypeBoolean = 'Boolean';
254 STypeMapPosition = 'Map position';
255 STypeImage = 'Image';
256 STypeDate = 'Date';
257 STypeTime = 'Time';
258 STypeDateTime = 'Date and time';
259 STypeReference = 'Reference';
260 SFieldNotFound = 'Field %s not found';
261
262
263implementation
264
265uses
266 UDataTypes, UEngineXML, UEngineMySQL, UEngineSQLite, UDbClientRegistry;
267
268{ TDbManager }
269
270procedure TDbManager.InitClientTypes;
271var
272 ClientType: TDbClientType;
273begin
274 ClientTypes.Clear;
275
276 ClientType := ClientTypes.RegisterClientType('XML file', TDatabaseXML, TDbConnectParamsXml);
277 ClientType.UseTypes(DataTypes, [ftString, ftInteger, ftDateTime, ftBoolean, ftFloat]);
278
279 ClientType := ClientTypes.RegisterClientType('MySQL', TDatabaseMySQL, TDbConnectParamsMySql);
280 ClientType.UseTypes(DataTypes, [ftString, ftInteger, ftDateTime, ftBoolean, ftFloat,
281 ftReference]);
282
283 ClientType := ClientTypes.RegisterClientType('SQLite', TDatabaseSQLite, TDbConnectParamsSqlite);
284 ClientType.UseTypes(DataTypes, [ftString, ftInteger, ftDateTime, ftBoolean, ftFloat]);
285
286 ClientType := ClientTypes.RegisterClientType('Registry', TDbClientRegistry, TDbConnectParamsRegistry);
287 ClientType.UseTypes(DataTypes, [ftString, ftInteger]);
288end;
289
290procedure TDbManager.InitDataTypes;
291begin
292 DataTypes.Clear;
293 with DataTypes do begin
294 RegisterType(1, 'String', STypeString, ftString, TFieldString);
295 RegisterType(2, 'Integer', STypeInteger, ftInteger, TFieldInteger);
296 RegisterType(3, 'DateTime', STypeDateTime, ftDateTime, TFieldDateTime);
297 RegisterType(4, 'Boolean', STypeBoolean, ftBoolean, TFieldBoolean);
298 RegisterType(5, 'Float', STypeFloat, ftFloat, TFieldFloat);
299 RegisterType(6, 'MapPosition', STypeMapPosition, ftMapPosition, TFieldMapPosition);
300 RegisterType(7, 'Date', STypeDate, ftDate, TFieldDate);
301 RegisterType(8, 'Time', STypeTime, ftTime, TFieldTime);
302 RegisterType(9, 'Image', STypeImage, ftImage, TFieldImage);
303 RegisterType(10, 'Reference', STypeReference, ftReference, TFieldReference);
304 end;
305end;
306
307constructor TDbManager.Create;
308begin
309 ConnectProfiles := TDbConnectProfiles.Create;
310 ConnectProfiles.DbManager := Self;
311 ClientTypes := TDbClientTypes.Create;
312 DataTypes := TDataTypes.Create;
313 InitDataTypes;
314 InitClientTypes;
315end;
316
317destructor TDbManager.Destroy;
318begin
319 FreeAndNil(DataTypes);
320 FreeAndNil(ClientTypes);
321 FreeAndNil(ConnectProfiles);
322 inherited;
323end;
324
325{ TDbConnectParams }
326
327procedure TDbConnectParams.SetConnectionString(AValue: string);
328begin
329 if FConnectionString = AValue then Exit;
330 FConnectionString := AValue;
331end;
332
333function TDbConnectParams.GetConnectionString: string;
334begin
335 Result := FConnectionString;
336end;
337
338{ TDbConnectProfiles }
339
340procedure TDbConnectProfiles.LoadFromRegistry(Context: TRegistryContext);
341var
342 I: Integer;
343 ConnectProfile: TDbConnectProfile;
344 ClientType: TDbClientType;
345begin
346 with TRegistryEx.Create do
347 try
348 CurrentContext := Context;
349 Count := GetValue('Count', 0);
350 for I := 0 to Count - 1 do begin
351 OpenKey(Context.Key + '\Item' + IntToStr(I), True);
352 ClientType := DbManager.ClientTypes.FindByName(GetValue('ClientType', ''));
353 if not Assigned(ClientType) and (DbManager.ClientTypes.Count > 0) then
354 ClientType := TDbClientType(DbManager.ClientTypes[0]);
355
356 ConnectProfile := TDbConnectProfile.Create;
357 ConnectProfile.DbManager := DbManager;
358 ConnectProfile.ClientType := ClientType;
359 ConnectProfile.Name := GetValue('Name', '');
360 ConnectProfile.Params.ConnectionString := GetValue('ConnectionString', '');
361 Items[I] := ConnectProfile;
362 end;
363 finally
364 Free;
365 end;
366end;
367
368procedure TDbConnectProfiles.SaveToRegistry(Context: TRegistryContext);
369var
370 I: Integer;
371begin
372 with TRegistryEx.Create do
373 try
374 CurrentContext := Context;
375 SetValue('Count', Count);
376 for I := 0 to Count - 1 do begin
377 OpenKey(Context.Key + '\Item' + IntToStr(I), True);
378 SetValue('Name', Items[I].Name);
379 SetValue('ConnectionString', Items[I].Params.ConnectionString);
380 SetValue('ClientType', Items[I].ClientType.Name);
381 end;
382 finally
383 Free;
384 end;
385end;
386
387function TDbConnectProfiles.SearchByName(Name: string): TDbConnectProfile;
388var
389 I: Integer;
390begin
391 I := 0;
392 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
393 if (I < Count) then Result := Items[I]
394 else Result := nil;
395end;
396
397{ TDbConnectProfile }
398
399procedure TDbConnectProfile.SetClientType(AValue: TDbClientType);
400begin
401 if FClientType = AValue then Exit;
402 if Assigned(FClientType) then begin
403 FreeAndNil(Params);
404 end;
405 FClientType := AValue;
406 if Assigned(FClientType) then begin
407 Params := FClientType.ConnectParmasClass.Create;
408 end;
409end;
410
411destructor TDbConnectProfile.Destroy;
412begin
413 ClientType := nil;
414 if Assigned(Params) then Params.Free;
415 inherited;
416end;
417
418function TDbConnectProfile.GetClient: TDbClient;
419begin
420 Result := ClientType.DatabaseClientClass.Create;
421 Result.ConnectProfile := Self;
422 Result.DbManager := DbManager;
423end;
424
425{ TTables }
426
427function TTables.SearchByName(Name: string): TTable;
428var
429 I: Integer;
430begin
431 I := 0;
432 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
433 if I < Count then Result := Items[I]
434 else Result := nil;
435end;
436
437function TTables.AddNew(Name: string): TTable;
438begin
439 Result := TTable.Create;
440 Result.DbClient := DbClient;
441 Result.Name := Name;
442 Add(Result);
443end;
444
445{ TDbClient }
446
447function TDbClient.GetClientType: TDbClientType;
448begin
449 Result := FConnectProfile.ClientType;
450end;
451
452procedure TDbClient.SetConnectProfile(AValue: TDbConnectProfile);
453begin
454 if FConnectProfile = AValue then Exit;
455 FConnectProfile := AValue;
456end;
457
458procedure TDbClient.Query(Text: string; DbRows: TDbRows = nil);
459begin
460end;
461
462constructor TDbClient.Create;
463begin
464 inherited;
465end;
466
467procedure TDbClient.Load;
468begin
469end;
470
471procedure TDbClient.Save;
472begin
473end;
474
475{ TDbClientTypes }
476
477function TDbClientTypes.RegisterClientType(Name: string;
478 DatabaseClass: TDbClientClass; ConnectParamsClass: TDbConnectParamsClass): TDbClientType;
479begin
480 Result := TDbClientType.Create;
481 Result.Name := Name;
482 Result.DatabaseClientClass := DatabaseClass;
483 Result.ConnectParmasClass := ConnectParamsClass;
484 Add(Result);
485end;
486
487function TDbClientTypes.FindByName(Name: string): TDbClientType;
488var
489 I: Integer;
490begin
491 I := 0;
492 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
493 if I < Count then Result := Items[I]
494 else Result := nil;
495end;
496
497{ TDataTypes }
498
499function TDataTypes.RegisterType(Id: Integer; Name, Title: string;
500 FieldType: TFieldType; FieldTypeClass: TFieldTypeSpecificClass): TDataType;
501begin
502 Result := TDataType.Create;
503 Result.Id := Id;
504 Result.Name := Name;
505 Result.Title := Title;
506 Result.FieldType := FieldType;
507 Result.FieldTypeClass := FieldTypeClass;
508 Add(Result);
509end;
510
511function TDataTypes.SearchByType(FieldType: TFieldType): TDataType;
512var
513 I: Integer;
514begin
515 I := 0;
516 while (I < Count) and (Items[I].FieldType <> FieldType) do Inc(I);
517 if I < Count then Result := Items[I]
518 else Result := nil;
519end;
520
521function TDataTypes.SearchByName(Name: string): TDataType;
522var
523 I: Integer;
524begin
525 I := 0;
526 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
527 if I < Count then Result := Items[I]
528 else Result := nil;
529end;
530
531{ TDbClientType }
532
533procedure TDbClientType.UseTypes(ADataTypes: TDataTypes; Types: TFieldTypeSet);
534var
535 I: TFieldType;
536begin
537 DataTypes.Clear;
538 for I := Low(TFieldType) to High(TFieldType) do
539 if I in Types then DataTypes.Add(ADataTypes.SearchByType(I));
540end;
541
542constructor TDbClientType.Create;
543begin
544 DataTypes := TDataTypes.Create;
545 DataTypes.OwnsObjects := False;
546end;
547
548destructor TDbClientType.Destroy;
549begin
550 FreeAndNil(DataTypes);
551 inherited;
552end;
553
554{ TValues }
555
556procedure TValues.Assign(Source: TValues);
557var
558 I: Integer;
559 OldCount: Integer;
560begin
561 OldCount := Count;
562 Count := Source.Count;
563 for I := OldCount to Count - 1 do
564 Items[I] := TValueClass(Source.Items[I].ClassType).Create;
565 for I := 0 to Count - 1 do
566 if TValue(Items[I]).ClassType <> Source.Items[I].ClassType then begin
567 Items[I] := TValueClass(Source.Items[I].ClassType).Create;
568 end;
569 for I := 0 to Source.Count - 1 do begin
570 Items[I].Assign(Source.Items[I]);
571 end;
572end;
573
574{ TRecords }
575
576procedure TRecords.Assign(Source: TRecords);
577var
578 I: Integer;
579 OldCount: Integer;
580begin
581 OldCount := Count;
582 Count := Source.Count;
583 for I := OldCount to Count - 1 do
584 Items[I] := TRecord.Create;
585 for I := 0 to Source.Count - 1 do begin
586 Items[I].Assign(Source.Items[I]);
587 end;
588end;
589
590function TRecords.SearchByValue(Name, Value: string): TRecord;
591var
592 I: Integer;
593 FieldIndex: Integer;
594 Field: TField;
595begin
596 Result := nil;
597 Field := Table.Fields.SearchByName(Name);
598 if Assigned(Field) then begin
599 FieldIndex := Table.Fields.IndexOf(Field);
600 I := 0;
601 while (I < Count) and (Items[I].Values[FieldIndex].GetString <> Value) do Inc(I);
602 if I < Count then Result := Items[I]
603 else Result := nil;
604 end;
605end;
606
607function TRecords.SearchByValues(Values: TStrings): TRecord;
608var
609 I: Integer;
610begin
611 Result := nil;
612 I := 0;
613 while (I < Count) and (Items[I].Match(Values)) do Inc(I);
614 if I < Count then Result := Items[I]
615 else Result := nil;
616end;
617
618function TRecords.AddNew: TRecord;
619begin
620 Result := TRecord.Create;
621 Result.Table := Table;
622 Result.InitValues;
623 Add(Result);
624end;
625
626procedure TRecords.Load;
627var
628 DbRows: TDbRows;
629 I: Integer;
630 F: Integer;
631 NewRecord: TRecord;
632 NewValue: TValue;
633 Value: string;
634begin
635 Clear;
636 DbRows := TDbRows.Create;
637 try
638 Table.DbClient.Query('SELECT * FROM ' + Table.Name, DbRows);
639 for I := 0 to DbRows.Count - 1 do begin
640 NewRecord := TRecord.Create;
641 for F := 0 to Table.Fields.Count - 1 do begin
642 NewValue := Table.Fields[F].GetValueClass.Create;
643 if DbRows[I].TryGetValue(Table.Fields[F].Name, Value) then begin
644 NewValue.SetString(Value);
645 NewRecord.Values.Add(NewValue);
646 end else begin
647 //NewValue.SetString('');
648 NewRecord.Values.Add(NewValue);
649 end;
650 end;
651 Add(NewRecord);
652 end;
653 finally
654 DbRows.Free;
655 end;
656end;
657
658{ TFields }
659
660function TFields.SearchByName(Name: string): TField;
661var
662 I: Integer;
663begin
664 I := 0;
665 while (I < Count) and (Items[I].Name <> Name) do Inc(I);
666 if I < Count then Result := Items[I]
667 else Result := nil;
668end;
669
670procedure TFields.Assign(Source: TFields);
671var
672 I: Integer;
673 OldCount: Integer;
674begin
675 OldCount := Count;
676 Count := Source.Count;
677 for I := OldCount to Count - 1 do
678 Items[I] := TField.Create;
679 for I := 0 to Source.Count - 1 do begin
680 Items[I].Assign(Source.Items[I]);
681 end;
682end;
683
684function TFields.AddNew(Name: string; DataType: TDataType): TField;
685begin
686 Result := TField.Create;
687 Result.Table := Table;
688 Result.Name := Name;
689 Result.DataType := DataType;
690 Add(Result);
691end;
692
693procedure TFields.Load;
694var
695 DbRows: TDbRows;
696 NewField: TField;
697 I: Integer;
698begin
699 Clear;
700 DbRows := TDbRows.Create;
701 try
702 Table.DbClient.Query('SELECT * FROM ModelField WHERE Model = ' + Table.Name, DbRows);
703 for I := 0 to DbRows.Count - 1 do begin
704 NewField := AddNew(DbRows[I].Items['Name'],
705 Table.DbClient.DbManager.DataTypes.SearchByName(DbRows[I].Items['DataType']));
706 NewField.TextBefore := DbRows[I].Items['Caption'];
707 end;
708 finally
709 DbRows.Free;
710 end;
711end;
712
713{ TRecord }
714
715function TRecord.Match(AValues: TStrings): Boolean;
716var
717 I: Integer;
718 Field: TField;
719 FieldIndex: Integer;
720begin
721 Result := True;
722 for I := 0 to aValues.Count - 1 do begin
723 Field := Table.Fields.SearchByName(AValues.Names[I]);
724 FieldIndex := Table.Fields.IndexOf(Field);
725 if Assigned(Field) then begin
726 if Values[FieldIndex].GetString <> AValues.ValueFromIndex[I] then begin
727 Result := False;
728 Break;
729 end;
730 end else raise Exception.Create(Format(SFieldNotFound, [AValues.Names[I]]));
731 end;
732end;
733
734procedure TRecord.InitValues;
735var
736 I: Integer;
737begin
738 Values.Clear;
739 for I := 0 to Table.Fields.Count - 1 do
740 Values.Add(Table.Fields[I].GetValueClass.Create);
741end;
742
743procedure TRecord.Assign(Source: TRecord);
744begin
745 Values.Assign(Source.Values);
746end;
747
748constructor TRecord.Create;
749begin
750 Values := TValues.Create;
751end;
752
753destructor TRecord.Destroy;
754begin
755 FreeAndNil(Values);
756 inherited;
757end;
758
759{ TValue }
760
761procedure TValue.Assign(Source: TValue);
762begin
763end;
764
765function TValue.GetString: string;
766begin
767 Result := '';
768end;
769
770procedure TValue.SetString(Value: string);
771begin
772end;
773
774function TValue.GetStringSQL: string;
775begin
776 Result := '';
777end;
778
779procedure TValue.SetStringSQL(Value: string);
780begin
781end;
782
783{ TFieldTypeSpecific }
784
785procedure TFieldTypeSpecific.Assign(Source: TFieldTypeSpecific);
786begin
787end;
788
789function TFieldTypeSpecific.GetValueClass: TValueClass;
790begin
791 Result := TValue;
792end;
793
794{ TField }
795
796procedure TField.SetDataType(AValue: TDataType);
797begin
798 if FDataType = AValue then Exit;
799 if Assigned(TypeRelated) then TypeRelated.Free;
800 FDataType := AValue;
801 if Assigned(AValue) then
802 TypeRelated := AValue.FieldTypeClass.Create
803 else TypeRelated := nil;
804end;
805
806procedure TField.Assign(Source: TField);
807begin
808 Name := Source.Name;
809 DataType := Source.DataType;
810 TextAfter := Source.TextAfter;
811 TextBefore := Source.TextBefore;
812 Required := Source.Required;
813 ReadOnly := Source.ReadOnly;
814 Description := Source.Description;
815 AllowNull := Source.AllowNull;
816 TypeRelated.Assign(Source.TypeRelated);
817end;
818
819function TField.GetValueClass: TValueClass;
820begin
821 if Assigned(TypeRelated) then Result := TypeRelated.GetValueClass
822 else Result := TValue;
823end;
824
825constructor TField.Create;
826begin
827 TypeRelated := TFieldString.Create;
828end;
829
830destructor TField.Destroy;
831begin
832 DataType := nil;
833 inherited;
834end;
835
836procedure TTable.LoadRecordsCount;
837var
838 DbRows: TDbRows;
839begin
840 Records.Clear;
841 DbRows := TDbRows.Create;
842 try
843 DbClient.Query('SELECT COUNT(*) FROM ' + Name, DbRows);
844 if DbRows.Count = 1 then begin
845 RecordsCount := StrToInt(DbRows[0].Items['COUNT(*)']);
846 end else RecordsCount := 0;
847 finally
848 DbRows.Free;
849 end;
850end;
851
852procedure TTable.Assign(Source: TTable);
853begin
854 Name := Source.Name;
855 Caption := Source.Caption;
856 Fields.Assign(Source.Fields);
857 Records.Assign(Source.Records);
858end;
859
860constructor TTable.Create;
861begin
862 Records := TRecords.Create;
863 Records.Table := Self;
864 Fields := TFields.Create;
865 Fields.Table := Self;
866end;
867
868destructor TTable.Destroy;
869begin
870 FreeAndNil(Fields);
871 FreeAndNil(Records);
872 inherited;
873end;
874
875end.
876
Note: See TracBrowser for help on using the repository browser.